#include "mpi_lib.h"
#include "mpi.h"
#include "mpi_cmd.h"
#include "mpi_sys.h"
#include "mpi_venc.h"

#define VENC_STREAM_QP_MATRIX_SIZE    (128 * 1024)
#define VENC_TOTAL_QP_MATRIX_SIZE     (VENC_STREAM_QP_MATRIX_SIZE * MULTI_STREAM_MAX_NUM)
#define JPEG_QT_SIZE                  (128)
#define JPEG_QT_BUFFER_NUM            (4)
#define MAX_REF_FRAME_INTVL           (3)
#define VENC_H264_QP_MIN              (0)
#define VENC_H264_QP_MAX              (51)
#define MIN_I_QP_REDUCE               (1)
#define MIN_P_QP_REDUCE               (1)
#define MAX_I_QP_REDUCE               (10)
#define MAX_P_QP_REDUCE               (5)
#define MAX_QP                        (51)
#define MAX_ZOOM_IN_MAIN_BUFFER       (1100)
#define MAX_ZOOM_IN_PREVIEW_A_B       (500)
#define MAX_ZOOM_STEPS                (10)
#define SGKS_TOTAL_RESOLUTION_LIMIT   (1920*1080*3 + 1280*1024)        // 7,531,520
#define VENC_YUV_ENC_BUF_SIZE         ((1920*1088*3/2)*2)  /* malloc 3 frame 1080p buf for encoder(yuv420) */

#define GET_DSP_CMD_CODE(cmd_code, stream) ((cmd_code) | (((stream) & 0x3) << 30))
#define SGKS_VIDEO_MODE_GET_WIDTH(mode)    ((mode&0x00FFF000)>>10)
#define SGKS_VIDEO_MODE_GET_HEIGTH(mode)   ((mode&0x00000FFF)<<1)
#ifndef DIV_ROUND
#define DIV_ROUND(divident, divider)    (((divident)+((divider)>>1))/(divider))
#endif

#define SGKS_VIDEO_TYPE(type)         (type)
#define SGKS_VIDEO_TYPE_AUTO          SGKS_VIDEO_TYPE(0)
#define SGKS_VIDEO_TYPE_YUV_601       SGKS_VIDEO_TYPE(1)
#define SGKS_VIDEO_TYPE_YUV_656       SGKS_VIDEO_TYPE(2)
#define SGKS_VIDEO_TYPE_RGB_601       SGKS_VIDEO_TYPE(3)
#define SGKS_VIDEO_TYPE_RGB_656       SGKS_VIDEO_TYPE(4)
#define SGKS_VIDEO_TYPE_RGB_RAW       SGKS_VIDEO_TYPE(5)
#define SGKS_VIDEO_TYPE_YUV_BT1120    SGKS_VIDEO_TYPE(6)
#define SGKS_VIDEO_TYPE_RGB_BT1120    SGKS_VIDEO_TYPE(7)

static sgks_stream_encode_config_s g_encode_config[MULTI_STREAM_MAX_NUM] =
{
    {
        .h264_encode_config = {
            .id = MEDIA_MAIN_STREAM,
            .M = 1,
            .N = 30,
            .gop_model = MEDIA_GOP_SIMPLE,
            .idr_interval = 1,
            .bitrate_control = VENC_BRC_SCBR,
            .average_bitrate = 4000000,
            .qp_min_on_I = 1,
            .qp_max_on_I = 51,
            .qp_min_on_P = 1,
            .qp_max_on_P = 51,
            .qp_min_on_B = 1,
            .qp_max_on_B = 51,
            .adapt_qp = 2,
            .i_qp_reduce = 6,
            .p_qp_reduce = 3,
            .skip_flag = 0,
            .hflip = 0,
            .vflip = 0,
            .rotate_clockwise = 0,
            .chroma_format = VENC_H264_CHROMA_FORMAT_YUV420,
            .intra_refresh_mb_rows = 0,
            .au_type = 1,
            .qp_delta = {
                {0,    10,    20,    50},
                {0,    10,    20,    50},
                {0,    10,    20,    50}
            },
            .qp_roi_enable = 0,
             .intrabias_P = INTRABIAS_MIN,
              .intrabias_B = INTRABIAS_MIN,
               .enable_scene_detect = 0,
                .intra16x16_bias = -48,
                 .intra4x4_bias = 24,
                  .inter16x16_bias = 0,
                   .inter8x8_bias = 24,
                    .direct16x16_bias = 0,
                     .direct8x8_bias = 0,
                      .me_lambda_qp_offset = 0,
                       .slice_alpha_c0_offset_div2 = 3,
                        .slice_beta_offset_div2 = 3,
                     },
        .jpeg_encode_config = {
            .id = MEDIA_MAIN_STREAM,
            .chroma_format = VENC_JPEG_CHROMA_FORMAT_YUV420,
            .quality = 50,
        },
        .frame_rate_multiplication_factor = 1,
         .frame_rate_division_factor = 1,
      },
    {
        .h264_encode_config = {
            .id = MEDIA_2ND_STREAM,
            .M = 1,
            .N = 30,
            .gop_model = MEDIA_GOP_SIMPLE,
            .idr_interval = 1,
            .bitrate_control = VENC_BRC_SCBR,
            .average_bitrate = 2000000,
            .qp_min_on_I = 1,
            .qp_max_on_I = 51,
            .qp_min_on_P = 1,
            .qp_max_on_P = 51,
            .qp_min_on_B = 1,
            .qp_max_on_B = 51,
            .adapt_qp = 2,
            .i_qp_reduce = 6,
            .p_qp_reduce = 3,
            .skip_flag = 0,
            .hflip = 0,
            .vflip = 0,
            .rotate_clockwise = 0,
            .chroma_format = VENC_H264_CHROMA_FORMAT_YUV420,
            .intra_refresh_mb_rows = 0,
            .au_type = 1,
            .qp_delta = {
                {0,    10,    20,    50},
                {0,    10,    20,    50},
                {0,    10,    20,    50}
            },
            .qp_roi_enable = 0,
             .intrabias_P = INTRABIAS_MIN,
              .intrabias_B = INTRABIAS_MIN,
               .enable_scene_detect = 0,
                .intra16x16_bias = -48,
                 .intra4x4_bias = 24,
                  .inter16x16_bias = 0,
                   .inter8x8_bias = 24,
                    .direct16x16_bias = 0,
                     .direct8x8_bias = 0,
                      .me_lambda_qp_offset = 0,
                       .slice_alpha_c0_offset_div2 = 3,
                        .slice_beta_offset_div2 = 3,
                     },
        .jpeg_encode_config = {
            .id = MEDIA_2ND_STREAM,
            .chroma_format = VENC_JPEG_CHROMA_FORMAT_YUV420,
            .quality = 50,
        },
        .frame_rate_multiplication_factor = 1,
         .frame_rate_division_factor = 1,
      },
    {
        .h264_encode_config = {
            .id = MEDIA_3RD_STREAM,
            .M = 1,
            .N = 30,
            .gop_model = MEDIA_GOP_SIMPLE,
            .idr_interval = 1,
            .bitrate_control = VENC_BRC_SCBR,
            .average_bitrate = 1000000,
            .qp_min_on_I = 1,
            .qp_max_on_I = 51,
            .qp_min_on_P = 1,
            .qp_max_on_P = 51,
            .qp_min_on_B = 1,
            .qp_max_on_B = 51,
            .adapt_qp = 2,
            .i_qp_reduce = 6,
            .p_qp_reduce = 3,
            .skip_flag = 0,
            .hflip = 0,
            .vflip = 0,
            .rotate_clockwise = 0,
            .chroma_format = VENC_H264_CHROMA_FORMAT_YUV420,
            .intra_refresh_mb_rows = 0,
            .au_type = 1,
            .qp_delta = {
                {0,    10,    20,    50},
                {0,    10,    20,    50},
                {0,    10,    20,    50}
            },
            .qp_roi_enable = 0,
             .intrabias_P = INTRABIAS_MIN,
              .intrabias_B = INTRABIAS_MIN,
               .enable_scene_detect = 0,
                .intra16x16_bias = -48,
                 .intra4x4_bias = 24,
                  .inter16x16_bias = 0,
                   .inter8x8_bias = 24,
                    .direct16x16_bias = 0,
                     .direct8x8_bias = 0,
                      .me_lambda_qp_offset = 0,
                       .slice_alpha_c0_offset_div2 = 3,
                        .slice_beta_offset_div2 = 3,
                     },
        .jpeg_encode_config = {
            .id = MEDIA_3RD_STREAM,
            .chroma_format = VENC_JPEG_CHROMA_FORMAT_YUV420,
            .quality = 50,
        },
        .frame_rate_multiplication_factor = 1,
         .frame_rate_division_factor = 1,
      },
    {
        .h264_encode_config = {
            .id = MEDIA_4TH_STREAM,
            .M = 1,            //config to be I-frame only
            .N = 30,
            .gop_model = MEDIA_GOP_SIMPLE,
            .idr_interval = 1,
            .bitrate_control = VENC_BRC_SCBR,
            .average_bitrate = 500000,
            .qp_min_on_I = 1,
            .qp_max_on_I = 51,
            .qp_min_on_P = 1,
            .qp_max_on_P = 51,
            .qp_min_on_B = 1,
            .qp_max_on_B = 51,
            .adapt_qp = 2,
            .i_qp_reduce = 6,
            .p_qp_reduce = 3,
            .skip_flag = 0,
            .hflip = 0,
            .vflip = 0,
            .rotate_clockwise = 0,
            .chroma_format = VENC_H264_CHROMA_FORMAT_YUV420,
            .intra_refresh_mb_rows = 0,
            .au_type = 1,
            .qp_delta = {
                {0,    10,    20,    50},
                {0,    10,    20,    50},
                {0,    10,    20,    50}
            },
            .qp_roi_enable = 0,
             .intrabias_P = INTRABIAS_MIN,
              .intrabias_B = INTRABIAS_MIN,
               .enable_scene_detect = 0,
                .intra16x16_bias = -48,
                 .intra4x4_bias = 24,
                  .inter16x16_bias = 0,
                   .inter8x8_bias = 24,
                    .direct16x16_bias = 0,
                     .direct8x8_bias = 0,
                      .me_lambda_qp_offset = 0,
                       .slice_alpha_c0_offset_div2 = 3,
                        .slice_beta_offset_div2 = 3,
                     },
        .jpeg_encode_config = {
            .id = MEDIA_4TH_STREAM,
            .chroma_format = VENC_JPEG_CHROMA_FORMAT_YUV420,
            .quality = 50,
        },
        .frame_rate_multiplication_factor = 1,
         .frame_rate_division_factor = 1,
      },
  };

static u32 qp_for_vbr_lut[11][11] =
{
//      1080p SXGA 1280x960 720p XGA SVGA 576p 480p VGA CIF SIF
    {    31,   29,    27,    27,  26, 23,  23,  22, 22, 17, 16    },    // 256 kbps
    {    30,   26,    25,    25,  24, 22,  21,  20, 20, 16, 15    },    // 512 kbps
    {    28,   25,    24,    24,  23, 21,  20,  19, 19, 15, 14    },    // 768 kbps
    {    27,   24,    23,    23,  22, 20,  19,  18, 18, 14, 13    },    // 1 Mbps
    {    26,   24,    22,    22,  21, 19,  18,  17, 17, 12, 11    },    // 1.5 Mbps
    {    25,   23,    22,    21,  19, 18,  17,  16, 16, 11, 10    },    // 2 Mbps
    {    24,   22,    21,    20,  19, 17,  16,  15, 15,  9,  8    },    // 3 Mbps
    {    23,   21,    20,    19,  18, 16,  15,  14, 14,  8,  7    },    // 4 Mbps
    {    22,   20,    19,    18,  17, 15,  14,  13, 12,  5,  1    },    // 6 Mbps
    {    21,   19,    18,    17,  16, 14,  13,  12, 11,  1,  1    },    // 8 Mbps
    {    21,   18,    17,    16,  15, 13,  12,  11, 10,  1,  1    },    // 10 Mbps
};

// rate control variables
static u32 bitrate_table[11] =
{
    256000,     512000,     768000,                // < 1 Mbps
    1000000,    1500000,    2000000,     3000000,   // < 4 Mbps
    4000000,    6000000,    8000000,    10000000,   // < 12 Mbps
};

static u32 resolution_table[11] =
{
    1920 * 1080,   1280 * 1024,   1280 * 960,   1280 * 720,
    1024 * 768,     800 * 600,     720 * 576,    720 * 480,
    640 * 480,     352 * 288,     352 * 240,
};
static sgks_venc_h264_quality_s h264qp[4] =
{
    {23, 26, 30}, // poor
    {20, 23, 27},
    {18, 22, 26},
    {14, 17, 21}, //best
};
static u8 qconArr[4] = {3, 2, 1, 0};

static sgks_venc_digital_zoom_s  g_digital_zoom =
{
    .zoom_factor_x = (1 << 16),
    .zoom_factor_y = (1 << 16),
    .center_offset_x = 0,
    .center_offset_y = 0,
};

static sgks_venc_encode_limit_s g_encode_limit =
{
    .width_max = MAX_WIDTH_IN_FULL_FPS,
    .height_max = MAX_HEIGHT_IN_FULL_FPS,
    .width_min = MIN_WIDTH_IN_FULL_FPS,
    .height_min = MIN_HEIGHT_IN_FULL_FPS,
    .h264_rotate_width_min = MIN_H264_ROTATE_WIDTH_IN_FULL_FPS,
    .h264_rotate_height_min = MIN_H264_ROTATE_HEIGHT_IN_FULL_FPS,
};

static sgks_mpi_mem_s g_qp_matrix_map;
static int g_qp_matrix_size = 0;
static sgks_mpi_mem_s g_quant_matrix_addr;
static sgks_mpi_mem_s g_hor_still_warp_table;
static sgks_mpi_mem_s g_ver_still_warp_table;
static sgks_mpi_mem_s g_enc_buf_map;
static sgks_vi_src_capability_s g_vi_cap_ability[MAX_VI_NUM];

static sgks_mpi_venc_handle_s *pMpiVencHandle;
static inline sgks_vi_src_capability_s *venc_get_vi_capability(void);
static inline int venc_is_stream_in_h264_encoding(int stream);
static inline int venc_is_stream_in_encoding(int stream);
static int venc_calc_target_qp(u32 min_bitrate, u32 resolution, u32 *qp);
static int venc_alloc_jpeg_qt_matrix(void);
static int venc_cmd_update_encode_params(int stream, int flags);
static int venc_set_encode_fps(u32 idFormat, u32 fpsTime, u32 viFrameRateTime);
static int venc_check_framerate_factor_ex(sgks_mpi_venc_change_framerate_factor_s *framerate);
static int venc_check_encode_resource_limit(u32 encode_stream_id, u32 vi_fps);
static int venc_update_system_source_buffer_format_all( sgks_source_buffer_format_all_s *format);
static int venc_cmd_capture_preview_buffer_setup(int buffer_id);
static int venc_cmd_warp_control(sgks_venc_digital_zoom_s *digital_zoom);
static int venc_set_system_source_buffer_type_all(sgks_source_buffer_type_all_s *pSourceBufferType);
//static int venc_cmd_encode_size_setup(int stream);
static int venc_set_encode_format( sgks_mpi_venc_format_s *pVencFormatParam);
static int venc_check_and_update_encode_resource(void);
static int venc_get_h264_config(sgks_venc_h264_config_s *pH264Config);
static int venc_set_h264_config(sgks_venc_h264_config_s  *pVencH264Config);
static int venc_change_qp_limit(sgks_venc_change_qp_limit_s *pVencQP);
static int venc_get_qp_limit(sgks_venc_change_qp_limit_s  *pVencQP);
static int venc_calc_dptz_i_param(sgks_venc_dptz_param_s *pVencDptz, sgks_venc_digital_zoom_s *pDptz);
static int venc_zoom_to_max_fov_keep_as(u32 idFormat);
static int venc_set_digital_zoom(sgks_venc_digital_zoom_s  *pDigitalZoom);
static int venc_set_2nd_digital_zoom_ex(sgks_venc_digital_zoom2_s  *pDigitalZoom2);
static int venc_calc_dptz_ii_param(sgks_venc_dptz_param_s *pVencDptz, sgks_venc_digital_zoom2_s *pDptz);
static int venc_cmd_jpeg_encode_setup(int stream, int is_mjpeg);
static int venc_cmd_h264_encode_setup(int stream);
static int venc_cmd_h264_encode_start(int stream);
static int venc_cmd_jpeg_encode_start(int stream);
static int venc_encode_start(u32 stream_id);
static int venc_cmd_encode_stop(int stream);
static int venc_encode_stop(u32 stream_id);


int sgks_mpi_venc_init()
{
    sgks_mpi_manager_s *mpi =NULL;

    pMpiVencHandle = (sgks_mpi_venc_handle_s *)sgks_mpi_Malloc(sizeof(sgks_mpi_venc_handle_s));
    if(pMpiVencHandle == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: Out of memory %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_MALLOCERR;
    }
    memset(pMpiVencHandle, 0x00, sizeof(sgks_mpi_venc_handle_s));

    mpi = mpi_get_managerHanle();
    if(mpi == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: mpi is null %s\n", __FUNCTION__));
        return SGKS_ERR_SYS_INITFAIL;
    }
#if 0
    if (sgks_mpi_sys_GetModuleInitStatus(mpi, MPI_MODULE_VENC_ID) != MPI_MODULE_STATUS_INIT)
    {
        mpi->curr_module_id = MPI_MODULE_VENC_ID;
        if(SGKS_SUCCESS != sgks_mpi_sys_GetDriverHandle(mpi))
        {
            DEBUGMSG(ZONE_ERROR, ("Get mdi driver handle fail\n"));
            return SGKS_ERR_VENC_DEVICEERR;
        }
        int ret = sgks_mpi_vi_OpenDeviceNode(mpi);
        if (ret != SGKS_SUCCESS)
        {
            return ret;
        }
    }
    else
    {
        mpi->curr_module_id = MPI_MODULE_VENC_ID;
        if(SGKS_SUCCESS != sgks_mpi_sys_GetDriverHandle(mpi))
        {
            DEBUGMSG(ZONE_ERROR, ("Get mdi driver handle fail\n"));
            return SGKS_ERR_VENC_DEVICEERR;
        }
    }
    pMpiVencHandle->hMDI = mpi->driver_handle[MPI_MODULE_VENC_ID];
#else
    pMpiVencHandle->hMDI = open(MPI_DRIVER_MEDIA_DEV, O_RDWR, 0);
    if(pMpiVencHandle->hMDI < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("err open mpi driver dev:%s\n", MPI_DRIVER_MEDIA_DEV));
        return SGKS_ERR_SYS_OPENDRIVERDEVERR;
    }
#endif
    pMpiVencHandle->activeEncodingNum = 0;

    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].config = &g_encode_config[VENC_STREAM_FIRST];
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].config = &g_encode_config[VENC_STREAM_SECOND];
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].config = &g_encode_config[VENC_STREAM_THIRD];
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].config = &g_encode_config[VENC_STREAM_FORTH];

    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].state = VENC_STREAM_STATE_READY_FOR_ENCODING;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].state = VENC_STREAM_STATE_READY_FOR_ENCODING;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].state = VENC_STREAM_STATE_READY_FOR_ENCODING;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].state = VENC_STREAM_STATE_READY_FOR_ENCODING;

    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].format.id = (1 << 0);
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].format.encode_width = 1920;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].format.encode_height = 1080;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].format.encode_type = SGKS_ENCODE_NONE;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].format.source = SGKS_ENCODE_SOURCE_MAIN_BUFFER;

    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].format.id      = (1 << 1);
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].format.encode_width = 640;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].format.encode_height = 360;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].format.encode_type = SGKS_ENCODE_NONE;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].format.source = SGKS_ENCODE_SOURCE_SECOND_BUFFER;

    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].format.id      = (1 << 2);
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].format.encode_width = 352;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].format.encode_height = 240;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].format.encode_type = SGKS_ENCODE_NONE;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].format.source = SGKS_ENCODE_SOURCE_MAIN_BUFFER;

    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].format.id      = (1 << 3);
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].format.encode_width = 352;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].format.encode_height = 240;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].format.encode_type = SGKS_ENCODE_NONE;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].format.source = SGKS_ENCODE_SOURCE_SECOND_BUFFER;


    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].bitrate.streamId = MEDIA_MAIN_STREAM;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].bitrate.brcMode = VENC_BRC_CBR;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].bitrate.cbrAvgBps = 4000000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].bitrate.vbrMinbps = 1000000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FIRST].bitrate.vbrMaxbps = 6000000;

    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].bitrate.streamId = MEDIA_2ND_STREAM;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].bitrate.brcMode = VENC_BRC_CBR;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].bitrate.cbrAvgBps = 2000000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].bitrate.vbrMinbps = 1000000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_SECOND].bitrate.vbrMaxbps = 6000000;

    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].bitrate.streamId = MEDIA_3RD_STREAM;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].bitrate.brcMode = VENC_BRC_CBR;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].bitrate.cbrAvgBps = 1000000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].bitrate.vbrMinbps = 500000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_THIRD].bitrate.vbrMaxbps = 2000000;

    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].bitrate.streamId = MEDIA_4TH_STREAM;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].bitrate.brcMode = VENC_BRC_CBR;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].bitrate.cbrAvgBps = 500000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].bitrate.vbrMinbps = 200000;
    pMpiVencHandle->encodeStreams[VENC_STREAM_FORTH].bitrate.vbrMaxbps = 1000000;

    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        g_qp_matrix_map.size = VENC_TOTAL_QP_MATRIX_SIZE;
        memcpy(msg_buf, (u8 *)&g_qp_matrix_map, sizeof(sgks_mdi_mem_s));
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_MALLOC, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
        memcpy((u8 *)&g_qp_matrix_map, msg_buf, sizeof(sgks_mdi_mem_s));
        memset(g_qp_matrix_map.user_addr, 0x00, VENC_TOTAL_QP_MATRIX_SIZE);
    }

    if(SGKS_SUCCESS != venc_alloc_jpeg_qt_matrix())
    {
        DEBUGMSG(ZONE_ERROR, ("mlloc jpeg qt matrix fail\n"));
        return SGKS_ERR_VENC_MALLOCERR;
    }

    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        sgks_mdi_mmap_s *mmap_info = msg_buf;
        mmap_info->mmap_phy_start_addr = (u8 *)mpi->mpi_init_param.dsp_init_param.msg_addr_arm_osd_phy;
        mmap_info->mmap_phy_size       = (int)mpi->mpi_init_param.dsp_init_param.msg_addr_arm_osd_size;
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_MMAP, 0, sizeof(sgks_mdi_mmap_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
        mpi->mpi_init_param.dsp_init_param.msg_addr_arm_osd_vir = (u32 *)mmap_info->mmap_user_start_addr;
    }

    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_SETENCODE, 0, 0, SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    sgks_mpi_sys_UpdateModuleInitStatus(mpi, MPI_MODULE_VENC_ID, MPI_MODULE_STATUS_INIT);
    DEBUGMSG(ZONE_INIT, ("%s end\n", __FUNCTION__));
    return SGKS_SUCCESS;
}

int sgks_mpi_venc_deinit()
{
    if(pMpiVencHandle != NULL)
    {
        sgks_mpi_Free(pMpiVencHandle);
        pMpiVencHandle = NULL;
    }

    if(g_qp_matrix_map.user_addr != NULL)
    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        memcpy(msg_buf, (u8 *)&g_qp_matrix_map, sizeof(sgks_mdi_mem_s));
        SGKS_MDI_DRV_IOCTL(SGKS_MDI_OPERATION_FREE, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    if(g_quant_matrix_addr.user_addr != NULL)
    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        memcpy(msg_buf, (u8 *)&g_quant_matrix_addr, sizeof(sgks_mdi_mem_s));
        SGKS_MDI_DRV_IOCTL(SGKS_MDI_OPERATION_FREE, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    if(g_hor_still_warp_table.user_addr != NULL)
    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        memcpy(msg_buf, (u8 *)&g_hor_still_warp_table, sizeof(sgks_mdi_mem_s));
        SGKS_MDI_DRV_IOCTL(SGKS_MDI_OPERATION_FREE, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    if(g_ver_still_warp_table.user_addr != NULL)
    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        memcpy(msg_buf, (u8 *)&g_ver_still_warp_table, sizeof(sgks_mdi_mem_s));
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_FREE, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }
    return SGKS_SUCCESS;
}

int sgks_mpi_venc_get_params(sgks_mpi_venc_param_type_e paramType, void *pParam)
{
    int ret = SGKS_SUCCESS;
    if(pParam == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: pParam is NULL %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }
    switch(paramType)
    {
        case VENC_PARAM_TYPE_BITRATE:
        {
            sgks_mpi_venc_bitrate_param_s *pVencBitrateParam = NULL;
            u32 stream_id = 0;

            pVencBitrateParam = (sgks_mpi_venc_bitrate_param_s *)pParam;
            stream_id = pVencBitrateParam->streamId;
            if(stream_id >= VENC_STREAM_NUM)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: stream id >= 4 %s %d\n", __FUNCTION__, __LINE__));
                return SGKS_ERR_VENC_PARAMERR;
            }
            memcpy(pVencBitrateParam, &pMpiVencHandle->encodeStreams[stream_id].bitrate, sizeof(sgks_mpi_venc_bitrate_param_s));
            break;
        }

        case VENC_PARAM_TYPE_FRAMERATE:
        {
            sgks_mpi_venc_framerate_param_s *pVencFramerateParam = NULL;
            u32 stream_id = 0;

            pVencFramerateParam = (sgks_mpi_venc_framerate_param_s *)pParam;
            stream_id = pVencFramerateParam->streamId;
            if(stream_id >= VENC_STREAM_NUM)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: stream id >= 4 %s %d\n", __FUNCTION__, __LINE__));
                return SGKS_ERR_VENC_PARAMERR;
            }
            pVencFramerateParam->fps = pMpiVencHandle->encodeStreams[stream_id].framerate;
            break;
        }

        case VENC_PARAM_TYPE_CHANNEL:
        {

            sgks_mpi_venc_channel_param_s *pChannelParam = NULL;
            sgks_source_buffer_format_ex_t *pSystemBuffFormat = NULL;
            sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
            pChannelParam = (sgks_mpi_venc_channel_param_s *)pParam;

            pChannelParam->chan1Type = mpi->system_source_buff[0].type;
            pChannelParam->chan2Type = mpi->system_source_buff[1].type;
            pChannelParam->chan3Type = mpi->system_source_buff[2].type;
            pChannelParam->chan4Type = mpi->system_source_buff[3].type;

            pSystemBuffFormat = &(mpi->system_source_buff[0].format);
            pChannelParam->chan1Width = pSystemBuffFormat->width;
            pChannelParam->chan1Height = pSystemBuffFormat->height;
            pChannelParam->chan1DeintlcForIntlcVin = pSystemBuffFormat->deintlc_for_intlc_vi;

            pSystemBuffFormat = &(mpi->system_source_buff[1].format);
            pChannelParam->chan2Width = pSystemBuffFormat->width;
            pChannelParam->chan2Height = pSystemBuffFormat->height;
            pChannelParam->chan2DeintlcForIntlcVin = pSystemBuffFormat->deintlc_for_intlc_vi;

            pSystemBuffFormat = &(mpi->system_source_buff[2].format);
            pChannelParam->chan3Width = pSystemBuffFormat->width;
            pChannelParam->chan3Height = pSystemBuffFormat->height;
            pChannelParam->chan3DeintlcForIntlcVin = pSystemBuffFormat->deintlc_for_intlc_vi;

            pSystemBuffFormat = &(mpi->system_source_buff[3].format);
            pChannelParam->chan4Width = pSystemBuffFormat->width;
            pChannelParam->chan4Height = pSystemBuffFormat->height;
            pChannelParam->chan4DeintlcForIntlcVin = pSystemBuffFormat->deintlc_for_intlc_vi;
            pChannelParam->intlcScan = pSystemBuffFormat->intlc_scan;
            break;
        }

        case VENC_PARAM_TYPE_STREAM:
        {
            sgks_mpi_venc_stream_format_param_s *pVencStreamFormatParam = NULL;
            sgks_mpi_venc_format_s *pVencFormat = NULL;
            sgks_venc_h264_config_s *pH264Config = NULL;
            u32 stream_id = 0;

            pVencStreamFormatParam = (sgks_mpi_venc_stream_format_param_s *)pParam;
            stream_id = pVencStreamFormatParam->streamId;

            pVencFormat = &(pMpiVencHandle->encodeStreams[stream_id].format);

            pVencStreamFormatParam->encodeType = pVencFormat->encode_type;
            pVencStreamFormatParam->channelId  = pVencFormat->source;

            pH264Config  = &(pMpiVencHandle->encodeStreams[stream_id].config->h264_encode_config);
            pVencStreamFormatParam->flipRotate = ((pH264Config->rotate_clockwise << 2) |
                                                  (pH264Config->vflip << 1) |
                                                  (pH264Config->hflip));

            pVencStreamFormatParam->width      = pVencFormat->encode_width;
            pVencStreamFormatParam->height     = pVencFormat->encode_height;
            pVencStreamFormatParam->xOffset    = pVencFormat->encode_x;
            pVencStreamFormatParam->yOffset    = pVencFormat->encode_y;
            pVencStreamFormatParam->fps        = pMpiVencHandle->encodeStreams[stream_id].framerate;
            pVencStreamFormatParam->keepAspRat = pMpiVencHandle->encodeStreams[stream_id].keepAspRat;

            break;
        }

        default:
        {
            DEBUGMSG(ZONE_ERROR, ("Error: paramType error %s\n", __FUNCTION__));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }

    return SGKS_SUCCESS;
}

int sgks_mpi_venc_set_params(sgks_mpi_venc_param_type_e paramType, void *pParam)
{
    int ret = SGKS_SUCCESS;
    if(pParam == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: pParam is NULL %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }
    switch(paramType)
    {
        case VENC_PARAM_TYPE_BITRATE:
        {
            sgks_mpi_venc_bitrate_param_s brInfo;
            sgks_mpi_venc_bitrate_param_s *pVencBitrateParam = NULL;
            sgks_venc_h264_config_s *h264 = NULL;
            int stream_id = 0;
            u32 enc_width = 0, enc_height = 0, resolution = 0, target_qp = 0;

            memcpy(&brInfo, (sgks_mpi_venc_bitrate_param_s *)pParam, sizeof(sgks_mpi_venc_bitrate_param_s));
            stream_id = brInfo.streamId;
            enc_width = pMpiVencHandle->encodeStreams[stream_id].format.encode_width;
            enc_height = pMpiVencHandle->encodeStreams[stream_id].format.encode_height;
            resolution = enc_width * enc_height;
            h264 = &g_encode_config[stream_id].h264_encode_config;
            switch(brInfo.brcMode)
            {
                case VENC_CBR_MODE:
                    h264->bitrate_control = VENC_BRC_SCBR;
                    h264->average_bitrate = brInfo.cbrAvgBps;
                    h264->qp_min_on_I = 1;
                    h264->qp_max_on_I = 51;
                    h264->qp_min_on_P = 1;
                    h264->qp_max_on_P = 51;
                    h264->qp_min_on_B = 1;
                    h264->qp_max_on_B = 51;
                    h264->skip_flag = 0;
                    break;
                case VENC_CBR_QUALITY_MODE:
                    if(venc_calc_target_qp(brInfo.cbrAvgBps, resolution, &target_qp) < 0)
                    {
                        DEBUGMSG(ZONE_ERROR, ("Error: param error %s - %s\n", __FUNCTION__, __LINE__));
                        return SGKS_ERR_VENC_PARAMERR;
                    }

                    h264->bitrate_control = VENC_BRC_SCBR;
                    h264->average_bitrate = brInfo.cbrAvgBps;
                    h264->qp_min_on_I = 1;
                    h264->qp_max_on_I = target_qp * 6 / 5;
                    h264->qp_min_on_P = 1;
                    h264->qp_max_on_P = target_qp * 6 / 5;
                    h264->qp_min_on_B = 1;
                    h264->qp_max_on_B = target_qp * 6 / 5;
                    h264->skip_flag = 6;        //enable frame dropping
                    break;
                case VENC_VBR_MODE:
                    if(venc_calc_target_qp(brInfo.cbrAvgBps, resolution, &target_qp) < 0)
                    {
                        DEBUGMSG(ZONE_ERROR, ("Error: param error %s - %s\n", __FUNCTION__, __LINE__));
                        return SGKS_ERR_VENC_PARAMERR;
                    }

                    h264->bitrate_control = VENC_BRC_SCBR;
                    h264->average_bitrate = brInfo.cbrAvgBps;
                    h264->qp_min_on_I = target_qp;
                    h264->qp_max_on_I = 51;
                    h264->qp_min_on_P = target_qp;
                    h264->qp_max_on_P = 51;
                    h264->qp_min_on_B = target_qp;
                    h264->qp_max_on_B = 51;
                    h264->skip_flag = 0;
                    break;
                case VENC_VBR_QUALITY_MODE:
                    if(venc_calc_target_qp(brInfo.cbrAvgBps, resolution, &target_qp) < 0)
                    {
                        DEBUGMSG(ZONE_ERROR, ("Error: param error %s - %s\n", __FUNCTION__, __LINE__));
                        return SGKS_ERR_VENC_PARAMERR;
                    }

                    h264->bitrate_control = VENC_BRC_SCBR;
                    h264->average_bitrate = brInfo.cbrAvgBps;
                    h264->qp_min_on_I = target_qp;
                    h264->qp_max_on_I = target_qp;
                    h264->qp_min_on_P = target_qp;
                    h264->qp_max_on_P = target_qp;
                    h264->qp_min_on_B = target_qp;
                    h264->qp_max_on_B = target_qp;
                    h264->skip_flag = 6;  //enable frame dropping
                    break;
                case VENC_CBR2_MODE:
                    h264->bitrate_control = VENC_BRC_CBR;
                    h264->average_bitrate = brInfo.cbrAvgBps;
                    break;
                case VENC_VBR2_MODE:        //to be done
                    DEBUGMSG(ZONE_ERROR, ("Error: param error %s - %s\n", __FUNCTION__, __LINE__));
                    return SGKS_ERR_VENC_PARAMERR;
                default:
                    DEBUGMSG(ZONE_ERROR, ("Unknown rate control mode!%s - %s\n", __FUNCTION__, __LINE__));
                    return SGKS_ERR_VENC_PARAMERR;
                    break;
            }

            if(venc_is_stream_in_h264_encoding(stream_id))
            {
                u32 flags = VENC_REALTIME_PARAM_CBR_MODIFY_BIT | VENC_REALTIME_PARAM_QP_LIMIT_BIT;
                ret = venc_cmd_update_encode_params(stream_id, flags);
            }

            pVencBitrateParam = &pMpiVencHandle->encodeStreams[stream_id].bitrate;
            memcpy(pVencBitrateParam, (sgks_mpi_venc_bitrate_param_s *)pParam, sizeof(sgks_mpi_venc_bitrate_param_s));
            break;
        }

        case VENC_PARAM_TYPE_FRAMERATE:
        {
            int framerateTime = 0;
            sgks_mpi_venc_framerate_param_s frInfo;
            memcpy(&frInfo, (sgks_mpi_venc_framerate_param_s *)pParam, sizeof(sgks_mpi_venc_framerate_param_s));
            framerateTime = sgks_mpi_vi_GetFramerateTime(frInfo.fps);
            if(framerateTime < 0)
            {
                DEBUGMSG(ZONE_ERROR, ("get framerate time failed, framerate:%d %S\n", frInfo.fps, __FUNCTION__));
                return SGKS_ERR_VENC_PARAMERR;
            }
            ret = venc_set_encode_fps(frInfo.streamId, framerateTime, venc_get_vi_capability()->frame_rate);
            pMpiVencHandle->encodeStreams[frInfo.streamId].framerate = frInfo.fps;
            break;
        }

        case VENC_PARAM_TYPE_CHANNEL:
        {
            sgks_source_buffer_format_all_s bufFormatAll;
            sgks_vi_src_capability_s *cur_vi_cap_ability = NULL;
            sgks_mpi_venc_channel_param_s *pChannelParam = (sgks_mpi_venc_channel_param_s *)pParam;
            sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

            cur_vi_cap_ability = venc_get_vi_capability();
            if(cur_vi_cap_ability == NULL)
            {
                DEBUGMSG(ZONE_ERROR, ("%s:get vi capability fail\n", __FUNCTION__));
                return SGKS_ERR_VENC_DEVICEERR;
            }

            if(mpi->vi_device.vi_deviceinfo[0].enable == 1)
            {
                if(pChannelParam->chan1Width > cur_vi_cap_ability->cap_width || pChannelParam->chan1Height > cur_vi_cap_ability->cap_height)
                {
                    DEBUGMSG(ZONE_ERROR, ("Error:stream 0 encode size > vin size!\n"));
                    return SGKS_ERR_VENC_PARAMERR;
                }
            }

            if(mpi->vi_device.vi_deviceinfo[1].enable == 1)
            {
                if(pChannelParam->chan2Width > cur_vi_cap_ability->cap_width || pChannelParam->chan2Height > cur_vi_cap_ability->cap_height)
                {
                    DEBUGMSG(ZONE_ERROR, ("Error:stream 1 encode size > vin size!\n"));
                    return SGKS_ERR_VENC_PARAMERR;
                }
            }

            bufFormatAll.main_width  = pChannelParam->chan1Width;
            bufFormatAll.main_height = pChannelParam->chan1Height;
            bufFormatAll.main_deintlc_for_intlc_vi = pChannelParam->chan1DeintlcForIntlcVin;
            bufFormatAll.second_width  = pChannelParam->chan2Width;
            bufFormatAll.second_height = pChannelParam->chan2Height;
            bufFormatAll.second_deintlc_for_intlc_vi = pChannelParam->chan2DeintlcForIntlcVin;
            bufFormatAll.third_width  = pChannelParam->chan3Width;
            bufFormatAll.third_height = pChannelParam->chan3Height;
            bufFormatAll.third_deintlc_for_intlc_vi = pChannelParam->chan3DeintlcForIntlcVin;
            bufFormatAll.fourth_width  = pChannelParam->chan4Width;
            bufFormatAll.fourth_height = pChannelParam->chan4Height;
            bufFormatAll.fourth_deintlc_for_intlc_vi = pChannelParam->chan4DeintlcForIntlcVin;
            bufFormatAll.intlc_scan = pChannelParam->intlcScan;
            bufFormatAll.second_input_width  = bufFormatAll.main_width;
            bufFormatAll.second_input_height = bufFormatAll.main_height;
            bufFormatAll.third_input_width   = bufFormatAll.main_width;
            bufFormatAll.third_input_height  = bufFormatAll.main_height;
            bufFormatAll.fourth_input_width  = bufFormatAll.main_width;
            bufFormatAll.fourth_input_height = bufFormatAll.main_height;
            venc_update_system_source_buffer_format_all(&bufFormatAll);

            sgks_source_buffer_type_all_s sourceBufferType;
            sourceBufferType.main_buffer_type   = pChannelParam->chan1Type;
            sourceBufferType.second_buffer_type = pChannelParam->chan2Type;
            sourceBufferType.third_buffer_type  = pChannelParam->chan3Type;
            sourceBufferType.fourth_buffer_type = pChannelParam->chan4Type;
            ret = venc_set_system_source_buffer_type_all(&sourceBufferType);
            break;
        }

        case VENC_PARAM_TYPE_STREAM:
        {
            //sgks_mpi_venc_stream_format_param_s streamFormatInfo;
            sgks_mpi_venc_stream_format_param_s *pVencStreamFormatParam = NULL;
            sgks_mpi_venc_format_s *pVencFormat = NULL;
            sgks_venc_h264_config_s *pH264Config = NULL;
            sgks_venc_mjpeg_config_s *pMjpegConfig = NULL;
            sgks_mpi_venc_stream_params_s *pVencStreamsParam = NULL;
            u8 hFlip, vFlip, rotate;
            int framerateTime = 0;

            pVencStreamFormatParam = (sgks_mpi_venc_stream_format_param_s *)pParam;

            pVencStreamsParam = &(pMpiVencHandle->encodeStreams[pVencStreamFormatParam->streamId]);
            pVencFormat = &(pMpiVencHandle->encodeStreams[pVencStreamFormatParam->streamId].format);
            pH264Config  = &(pMpiVencHandle->encodeStreams[pVencStreamFormatParam->streamId].config->h264_encode_config);
            pMjpegConfig = &(pMpiVencHandle->encodeStreams[pVencStreamFormatParam->streamId].config->jpeg_encode_config);

            pVencFormat->id = 1 << pVencStreamFormatParam->streamId;
            pVencFormat->encode_type   = pVencStreamFormatParam->encodeType;
            pVencFormat->source        = pVencStreamFormatParam->channelId;
            pVencFormat->encode_width  = pVencStreamFormatParam->width;
            pVencFormat->encode_height = pVencStreamFormatParam->height;
            pVencFormat->encode_x      = pVencStreamFormatParam->xOffset;
            pVencFormat->encode_y      = pVencStreamFormatParam->yOffset;

            hFlip  = ((pVencStreamFormatParam->flipRotate & 0x1) != 0);
            vFlip  = ((pVencStreamFormatParam->flipRotate & 0x2) != 0);
            rotate = ((pVencStreamFormatParam->flipRotate & 0x4) != 0);
            pH264Config->hflip  = hFlip;
            pH264Config->vflip  = vFlip;
            pH264Config->rotate_clockwise = rotate;

            pMjpegConfig->hflip = hFlip;
            pMjpegConfig->vflip = vFlip;
            pMjpegConfig->rotate_clockwise = rotate;

            if(rotate)
            {
                if(pVencStreamsParam->maxWidth < pVencFormat->encode_height)
                {
                    pVencStreamsParam->maxWidth = pVencFormat->encode_height;
                }

                if(pVencStreamsParam->maxHeight < pVencFormat->encode_width)
                {
                    pVencStreamsParam->maxHeight = pVencFormat->encode_width;
                }
            }
            else
            {
                if(pVencStreamsParam->maxWidth < pVencFormat->encode_width)
                {
                    pVencStreamsParam->maxWidth = pVencFormat->encode_width;
                }

                if(pVencStreamsParam->maxHeight < pVencFormat->encode_height)
                {
                    pVencStreamsParam->maxHeight = pVencFormat->encode_height;
                }
            }

            venc_check_and_update_encode_resource();/*check resource limit*/

            framerateTime = sgks_mpi_vi_GetFramerateTime(pVencStreamFormatParam->fps);/*set frame rate.*/
            if(framerateTime < 0)
            {
                DEBUGMSG(ZONE_ERROR, ("VENC: get framerate time failed, framerate:%d\n", pVencStreamFormatParam->fps));
                return SGKS_ERR_VENC_PARAMERR;
            }

            ret = venc_set_encode_fps(pVencStreamFormatParam->streamId, framerateTime, venc_get_vi_capability()->frame_rate);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("%s venc_set_encode_fps fail\n", __FUNCTION__));
                return ret;
            }

            pVencStreamsParam->framerate  = pVencStreamFormatParam->fps;
            pVencStreamsParam->keepAspRat = pVencStreamFormatParam->keepAspRat;
            ret = venc_set_encode_format(pVencStreamFormatParam);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("%s venc_set_encode_format fail\n", __FUNCTION__));
                return ret;
            }
            break;
        }

        default:
        {
            DEBUGMSG(ZONE_ERROR, ("Error: paramType error %s\n", __FUNCTION__));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }
    return ret;
}

int sgks_mpi_venc_set_config(sgks_mpi_venc_config_type_e configType, void *pConfig)
{
    int ret = SGKS_SUCCESS;
    if(pConfig == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: pParam is NULL %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }
    switch(configType)
    {
        case VENC_CONFIG_TYPE_H264:
        {
            sgks_mpi_venc_h264_config_s *pMpiVencH264ConfigParam = NULL;
            sgks_venc_h264_config_s VencH264ConfigTemp;
            sgks_mpi_venc_bitrate_param_s bps;
            sgks_venc_change_qp_limit_s pqLimit;
            u32 stream_id = 0;
            u8 qbIndex = 0;

            pMpiVencH264ConfigParam = (sgks_mpi_venc_h264_config_s *)pConfig;
            stream_id = pMpiVencH264ConfigParam->streamId;

            VencH264ConfigTemp.id = pMpiVencH264ConfigParam->streamId;
            ret = venc_get_h264_config(&VencH264ConfigTemp);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: get h264 config return error\r\n", __FUNCTION__));
                return ret;
            }
            VencH264ConfigTemp.id = pMpiVencH264ConfigParam->streamId;
            VencH264ConfigTemp.M = pMpiVencH264ConfigParam->gopM;
            VencH264ConfigTemp.N = pMpiVencH264ConfigParam->gopN;
            VencH264ConfigTemp.idr_interval = pMpiVencH264ConfigParam->idrInterval;
            VencH264ConfigTemp.gop_model = pMpiVencH264ConfigParam->gopModel;
            VencH264ConfigTemp.entropy_codec = pMpiVencH264ConfigParam->profile;
            VencH264ConfigTemp.bitrate_control = VENC_BRC_SCBR;
            if(pMpiVencH264ConfigParam->brcMode & 0x1)
            {
                VencH264ConfigTemp.average_bitrate = pMpiVencH264ConfigParam->vbrMaxbps;
            }
            else
            {
                VencH264ConfigTemp.average_bitrate = pMpiVencH264ConfigParam->cbrAvgBps;
            }
            VencH264ConfigTemp.adapt_qp = qconArr[pMpiVencH264ConfigParam->qcon];

            qbIndex = pMpiVencH264ConfigParam->adaptQp;
            if((pMpiVencH264ConfigParam->qpMinI > pMpiVencH264ConfigParam->qpMinP) ||
               ((pMpiVencH264ConfigParam->qpMinI == 0) && (pMpiVencH264ConfigParam->qpMinP == 0)) ||
               (pMpiVencH264ConfigParam->qpMinI > MAX_QP) ||
               (pMpiVencH264ConfigParam->qpMinP > MAX_QP))
            {
                VencH264ConfigTemp.qp_min_on_I = h264qp[qbIndex].qp_min_I ;
                VencH264ConfigTemp.qp_min_on_B = h264qp[qbIndex].qp_min_B ;
                VencH264ConfigTemp.qp_min_on_P = h264qp[qbIndex].qp_min_P;
            }
            else
            {
                VencH264ConfigTemp.qp_min_on_I = pMpiVencH264ConfigParam->qpMinI;
                VencH264ConfigTemp.qp_min_on_P = pMpiVencH264ConfigParam->qpMinP;
                VencH264ConfigTemp.qp_min_on_B = h264qp[qbIndex].qp_min_B ;
            }

            /*replace default value when set qpIWeight or qpPWeight in reasonable range.*/
            if((pMpiVencH264ConfigParam->qpIWeight >= MIN_I_QP_REDUCE) &&
               (pMpiVencH264ConfigParam->qpIWeight <= MAX_I_QP_REDUCE) &&
               (pMpiVencH264ConfigParam->qpPWeight >= MIN_P_QP_REDUCE) &&
               (pMpiVencH264ConfigParam->qpPWeight <= MAX_P_QP_REDUCE))
            {
                VencH264ConfigTemp.i_qp_reduce = pMpiVencH264ConfigParam->qpIWeight;
                VencH264ConfigTemp.p_qp_reduce = pMpiVencH264ConfigParam->qpPWeight;
            }

            ret = venc_set_h264_config(&VencH264ConfigTemp);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: set h264 config return error\r\n", __FUNCTION__));
                return ret;
            }

            bps.streamId = pMpiVencH264ConfigParam->streamId;
            bps.brcMode = pMpiVencH264ConfigParam->brcMode;
            bps.cbrAvgBps   = pMpiVencH264ConfigParam->cbrAvgBps;
            bps.vbrMinbps   = pMpiVencH264ConfigParam->vbrMinbps;
            bps.vbrMaxbps   = pMpiVencH264ConfigParam->vbrMaxbps;
            ret = sgks_mpi_venc_set_params(VENC_PARAM_TYPE_BITRATE, (void *)&bps);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: set h264 bitrate param return error\r\n", __FUNCTION__));
                return ret;
            }

            pqLimit.id = pMpiVencH264ConfigParam->streamId;
            ret = venc_get_qp_limit(&pqLimit);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: set get qp param return error\r\n", __FUNCTION__));
                return ret;
            }
            if((pMpiVencH264ConfigParam->qpMinI > pMpiVencH264ConfigParam->qpMinP) ||
               ((pMpiVencH264ConfigParam->qpMinI == 0) && (pMpiVencH264ConfigParam->qpMinP == 0)) ||
               (pMpiVencH264ConfigParam->qpMinI > MAX_QP) ||
               (pMpiVencH264ConfigParam->qpMinP > MAX_QP))
            {
                pqLimit.qp_min_on_I = h264qp[qbIndex].qp_min_I ;
                pqLimit.qp_min_on_B = h264qp[qbIndex].qp_min_B ;
                pqLimit.qp_min_on_P = h264qp[qbIndex].qp_min_P;
                pqLimit.adapt_qp    = qconArr[pMpiVencH264ConfigParam->qcon];
            }
            else
            {
                pqLimit.qp_min_on_I = pMpiVencH264ConfigParam->qpMinI;
                pqLimit.qp_min_on_P = pMpiVencH264ConfigParam->qpMinP;
                pqLimit.qp_min_on_B = h264qp[qbIndex].qp_min_B ;
                pqLimit.adapt_qp    = qconArr[pMpiVencH264ConfigParam->qcon];
            }

            if((pMpiVencH264ConfigParam->qpIWeight >= MIN_I_QP_REDUCE) &&
               (pMpiVencH264ConfigParam->qpIWeight <= MAX_I_QP_REDUCE) &&
               (pMpiVencH264ConfigParam->qpPWeight >= MIN_P_QP_REDUCE) &&
               (pMpiVencH264ConfigParam->qpPWeight <= MAX_P_QP_REDUCE))
            {
                pqLimit.i_qp_reduce = pMpiVencH264ConfigParam->qpIWeight;
                pqLimit.p_qp_reduce = pMpiVencH264ConfigParam->qpPWeight;
            }
            ret = venc_change_qp_limit(&pqLimit);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: set change qp param return error\r\n", __FUNCTION__));
                return ret;
            }
            break;
        }

        case VENC_CONFIG_TYPE_MJPEG:
        {
            sgks_mpi_venc_mjpeg_config_s *pVencMjpegConfigParam = NULL;
            sgks_venc_mjpeg_config_s *pMjpegConfig = NULL;
            u32 stream_id = 0;

            pVencMjpegConfigParam = (sgks_mpi_venc_mjpeg_config_s *)pConfig;
            /*check input parameters.*/
            if((pVencMjpegConfigParam->chromaFormat > 1) ||
               (pVencMjpegConfigParam->quality < 1) ||
               (pVencMjpegConfigParam->quality > 100))
            {
                DEBUGMSG(ZONE_ERROR, ("Input chromaFormat:%d,adaptQp:%d invalid\n", pVencMjpegConfigParam->chromaFormat, pVencMjpegConfigParam->quality));
                return SGKS_ERR_VENC_PARAMERR;
            }
            stream_id = pVencMjpegConfigParam->streamId;
            pMjpegConfig = &pMpiVencHandle->encodeStreams[stream_id].config->jpeg_encode_config;
            pMjpegConfig->chroma_format = pVencMjpegConfigParam->chromaFormat;
            pMjpegConfig->quality = pVencMjpegConfigParam->quality;
            pMjpegConfig->id = (1 << stream_id);
            if(venc_is_stream_in_encoding(stream_id))
            {
                if(venc_cmd_update_encode_params(stream_id, VENC_REALTIME_PARAM_QUANT_MATRIX_BIT) < 0)
                {
                    DEBUGMSG(ZONE_ERROR, ("Runtime change MJPEG quality error!\n"));
                    return SGKS_ERR_VENC_SENDCMDFAIL;
                }
            }
            break;
        }
        default:
        {
            DEBUGMSG(ZONE_ERROR, ("Error: configType error %s\n", __FUNCTION__));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }
    return ret;
}

int sgks_mpi_venc_get_config(sgks_mpi_venc_config_type_e configType, void *pConfig)
{
    int ret = SGKS_SUCCESS;
    if(pConfig == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: pParam is NULL %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }
    switch(configType)
    {
        case VENC_CONFIG_TYPE_H264:
        {
            sgks_mpi_venc_h264_config_s *pMpiVencH264ConfigParam = NULL;
            sgks_venc_h264_config_s VencH264Config;
            sgks_mpi_venc_bitrate_param_s bps;
            u8 qb_index = 0;

            pMpiVencH264ConfigParam = (sgks_mpi_venc_h264_config_s *)pConfig;
            VencH264Config.id = pMpiVencH264ConfigParam->streamId;
            ret = venc_get_h264_config(&VencH264Config);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: Can't get h264 config %s\n", __FUNCTION__));
                return ret;
            }
            pMpiVencH264ConfigParam->gopM = VencH264Config.M;
            pMpiVencH264ConfigParam->gopN = VencH264Config.N;
            pMpiVencH264ConfigParam->idrInterval = VencH264Config.idr_interval;
            pMpiVencH264ConfigParam->gopModel  = VencH264Config.gop_model;
            pMpiVencH264ConfigParam->profile   = VencH264Config.entropy_codec;
            pMpiVencH264ConfigParam->qpMinI    = VencH264Config.qp_min_on_I;
            pMpiVencH264ConfigParam->qpMinP    = VencH264Config.qp_min_on_P;
            pMpiVencH264ConfigParam->qpIWeight = VencH264Config.i_qp_reduce;
            pMpiVencH264ConfigParam->qpPWeight = VencH264Config.p_qp_reduce;

            bps.streamId = pMpiVencH264ConfigParam->streamId;
            ret = sgks_mpi_venc_get_params(VENC_PARAM_TYPE_BITRATE, (void * )&bps);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Error: Can't get bitrate %s\n", __FUNCTION__));
                return ret;
            }

            pMpiVencH264ConfigParam->brcMode   = bps.brcMode;
            pMpiVencH264ConfigParam->cbrAvgBps = bps.cbrAvgBps;
            pMpiVencH264ConfigParam->vbrMinbps = bps.vbrMinbps;
            pMpiVencH264ConfigParam->vbrMaxbps = bps.vbrMaxbps;
            if(VencH264Config.adapt_qp > 3)
            {
                VencH264Config.adapt_qp = 0; // poor
            }

            pMpiVencH264ConfigParam->qcon = qconArr[VencH264Config.adapt_qp];

            for(qb_index = 0; qb_index < 4; qb_index++)
            {
                if(h264qp[qb_index].qp_min_I == VencH264Config.qp_max_on_I &&
                   h264qp[qb_index].qp_min_B == VencH264Config.qp_max_on_B &&
                   h264qp[qb_index].qp_min_P == VencH264Config.qp_max_on_P)
                {
                    break;
                }
            }

            if(qb_index == 4)
            {
                qb_index = 3 ;    // best
            }

            pMpiVencH264ConfigParam->adaptQp = qb_index;
            break;

        }

        case VENC_CONFIG_TYPE_MJPEG:
        {
            sgks_mpi_venc_mjpeg_config_s *pVencMjpegConfigParam = NULL;
            sgks_venc_mjpeg_config_s *pMjpegConfig = NULL;
            u32 stream_id = 0;

            pVencMjpegConfigParam = (sgks_mpi_venc_mjpeg_config_s *)pConfig;
            stream_id = pVencMjpegConfigParam->streamId;
            pMjpegConfig = &(pMpiVencHandle->encodeStreams[stream_id].config->jpeg_encode_config);
            pVencMjpegConfigParam->chromaFormat = pMjpegConfig->chroma_format;
            pVencMjpegConfigParam->quality      = pMjpegConfig->quality;
            break;
        }
        default:
        {
            DEBUGMSG(ZONE_ERROR, ("Error: configType error %s\n", __FUNCTION__));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }
    return ret;
}

int sgks_mpi_venc_state_control(sgks_mpi_venc_state_control_type_e stateControlType, u32 streamId)
{
    int ret = SGKS_SUCCESS;

    switch(stateControlType)
    {
        case VENC_STATE_CONTROL_START:
        {
            u32 indexFormat = 0;
            int i = 0;

            indexFormat = 1 << streamId;
            for(i = 0; i < VENC_STREAM_NUM; ++i)
            {
                if(pMpiVencHandle->encodeStreams[streamId].state == VENC_STREAM_STATE_ENCODING)
                {
                    indexFormat &= ~(1 << i);
                }
            }
            if(indexFormat == 0)
            {
                DEBUGMSG(ZONE_INFO, ("%s:Stream %d is Encoding\n",  __FUNCTION__, streamId));
                return SGKS_SUCCESS;
            }
#if 1
            if(pMpiVencHandle->encodeStreams[streamId].keepAspRat > 0)
            {
                venc_zoom_to_max_fov_keep_as(indexFormat);
            }
#endif
            ret = venc_encode_start(indexFormat);
            break;
        }

        case VENC_STATE_CONTROL_STOP:
        {
            u32 indexFormat = 0;
            int i = 0, sys_status = 0;
            int ret = SGKS_SUCCESS;

            indexFormat = 1 << streamId;
            for(i = 0; i < VENC_STREAM_NUM; ++i)
            {
                if(pMpiVencHandle->encodeStreams[streamId].state != VENC_STREAM_STATE_ENCODING)
                {
                    indexFormat &= ~(1 << i);
                }
            }

            sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
            sgks_mpi_cmd_SetMode(mpi, SGKS_MDI_CMD_MODE_BLOCK_LOADING);

            ret = venc_encode_stop(indexFormat);
            sgks_mpi_cmd_SetMode(mpi, SGKS_MDI_CMD_MODE_BLOCK_READY);

            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("Stop encode fail %s\n", __FUNCTION__));
            }
            break;
        }

        default:
        {
            DEBUGMSG(ZONE_ERROR, ("Error: stateControlType error %s\n", __FUNCTION__));
            ret = SGKS_ERR_VENC_PARAMERR;
        }
    }

    return ret;
}

int sgks_mpi_venc_get_stream(u32 streamId, sgks_mpi_venc_stream_s *pStream)
{
    sgks_mdi_enc_bits_info  bits_info;
    u8 *msg_buf = NULL;
    static u32 init_flag = 0;
    static u32 frame_num[MULTI_STREAM_MAX_NUM];
    int i = 0;
    sgks_mpi_manager_s *mpi =NULL;

    if(init_flag == 0)
    {
        for(i = 0; i < MULTI_STREAM_MAX_NUM; ++i)
        {
            frame_num[i] = 0;
        }
        init_flag = 1;
    }

    SGKS_MDI_DRV_BUFF(msg_buf);
    memset(&bits_info, 0x00, sizeof(bits_info));
    memcpy(msg_buf, (u8 *)&bits_info, sizeof(bits_info));
    SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_READ_BITSTREAM, 0, sizeof(sgks_mdi_enc_bits_info), SGKS_ERR_SYS_DRIVERIOCTLERR);
    memcpy((u8 *)&bits_info, msg_buf, sizeof(bits_info));
    //DEBUGMSG(ZONE_INFO, ("mpi:num=%d, type=%d, addr=0x%x, size=0x%x\n", bits_info.frame_num, bits_info.pic_type, bits_info.start_addr, bits_info.pic_size));
    if(0xff == streamId)
    {
        pStream->stream_id = bits_info.stream_id;
    }
    else if((bits_info.stream_id == streamId) && (bits_info.stream_end != 1))
    {
        pStream->stream_id = streamId;
    }
    else
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    pStream->frame_num = frame_num[bits_info.stream_id];
    pStream->pic_type = bits_info.pic_type;
    pStream->PTS = bits_info.stream_pts;
    if(pStream->PTS == 0)
    {
        pStream->PTS = bits_info.PTS;
    }

    pStream->stream_end = bits_info.stream_end;
    pStream->addr = (u8 *)bits_info.start_addr;
    pStream->size = bits_info.pic_size;
    frame_num[bits_info.stream_id]++;
    return SGKS_SUCCESS;
}

int sgks_mpi_venc_get_state(u32 *state,  u32 streamId)
{
    int ret = SGKS_SUCCESS;
    if((state == NULL) || (streamId >=VENC_STREAM_NUM ))
    {
        DEBUGMSG(ZONE_ERROR, ("%s Param is error\n", __FUNCTION__));
        ret = SGKS_ERR_VENC_PARAMERR;
    }
#if 0
    sgks_mpi_venc_state_e  current_venc_state;
    sgks_mpi_dsp_status_s   dsp_state;

    dsp_state.op_mode = SGKS_DSP_UNKNOWN_MODE;
    dsp_state.op_sub_mode = SGKS_DSP_ENC_UNKNOWN_MODE;
    dsp_state.state = SGKS_ENC_UNKNOWN_STATE;

    current_venc_state = STATE_IDLE;
    ret = sgks_mpi_sys_GetDspStats(&dsp_state);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Get DSP STATE FAIL\n"));
        ret = SGKS_ERR_VENC_DEVICEERR;
    }

    if(dsp_state.op_mode == SGKS_DSP_ENCODE_MODE)
    {
        if(dsp_state.state == SGKS_ENC_IDLE_STATE)
        {
            current_venc_state = STATE_PREVIEW;
        }
        else if(dsp_state.state == SGKS_ENC_BUSY_STATE)
        {
            current_venc_state = STATE_ENCODING;
        }
    }
    *state = (u32)current_venc_state;
#endif
    *state = (u32)(pMpiVencHandle->encodeStreams[streamId].state);
    return ret;
}


static inline int venc_is_multi_stream_id(u32 stream_id)
{
    return ((stream_id & (stream_id - 1)) > 0);
}

static inline int venc_is_h264_stream(int stream)
{
    return (pMpiVencHandle->encodeStreams[stream].format.encode_type == SGKS_ENCODE_H264);
}

static inline int venc_is_stream_in_encoding(int stream)
{
    return (pMpiVencHandle->encodeStreams[stream].state == VENC_STREAM_STATE_ENCODING);
}

static inline int venc_is_mjpeg_stream(int stream)
{
    return (pMpiVencHandle->encodeStreams[stream].format.encode_type == SGKS_ENCODE_MJPEG);
}
static inline int venc_is_stream_in_encode_starting(int stream)
{
    return (pMpiVencHandle->encodeStreams[stream].state == VENC_STREAM_STATE_STARTING);
}

static inline int venc_is_stream_in_stopping(int stream)
{
    return (pMpiVencHandle->encodeStreams[stream].state == VENC_STREAM_STATE_STOPPING);
}

static inline int venc_is_stream_in_h264_encoding(int stream)
{
    return (venc_is_h264_stream(stream) && venc_is_stream_in_encoding(stream));
}

static int venc_search_nearest(u32 key, u32 arr[], int size, int order)
{
    int l = 0;
    int r = size - 1;
    int m = (l + r) / 2;

    if(order == 0)       //arr in ascending order
    {
        while(1)
        {
            if(l == r)
            {
                return l;
            }

            if(key > arr[m])
            {
                l = m + 1;
            }
            else if(key < arr[m])
            {
                r = m;
            }
            else
            {
                return m;
            }

            m = (l + r) / 2;
        }
    }
    else                //arr in descending order
    {
        while(1)
        {
            if(l == r)
            {
                return l;
            }

            if(key > arr[m])
            {
                r = m;
            }
            else if(key < arr[m])
            {
                l = m + 1;
            }
            else
            {
                return m;
            }

            m = (l + r) / 2;
        }
    }
    DEBUGMSG(ZONE_ERROR, ("Param Error %s\n", __FUNCTION__));
    return SGKS_ERR_VENC_PARAMERR;
}

static int venc_calc_target_qp(u32 min_bitrate, u32 resolution, u32 *qp)
{
    int bitrate_index, resolution_index;
    bitrate_index = venc_search_nearest(min_bitrate, bitrate_table, ARRAY_SIZE(bitrate_table), 0);
    resolution_index = venc_search_nearest(resolution, resolution_table, ARRAY_SIZE(resolution_table), 1);
    if((bitrate_index < 0) || (resolution_index < 0))
    {
        DEBUGMSG(ZONE_ERROR, ("Param Error %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    *qp = qp_for_vbr_lut[bitrate_index][resolution_index];
    return SGKS_SUCCESS;
}

static inline sgks_vi_src_capability_s *venc_get_vi_capability(void)
{
    int ret = 0;

    memset(g_vi_cap_ability, 0x00, sizeof(g_vi_cap_ability));
    ret = sgks_mpi_vi_GetSensorCapability(g_vi_cap_ability);
    if (ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: get vi cap ability fail %s\n", __FUNCTION__));
        return NULL;
    }
#if 0
    {
        DEBUGMSG(ZONE_INFO, ("VI:0 input_type=%d\n", g_vi_cap_ability[0].input_type));
        DEBUGMSG(ZONE_INFO, ("VI:0 dev_type=%d\n", g_vi_cap_ability[0].dev_type));
        DEBUGMSG(ZONE_INFO, ("VI:0 frame_rate=%d\n", g_vi_cap_ability[0].frame_rate));
        DEBUGMSG(ZONE_INFO, ("VI:0 video_format=%d\n", g_vi_cap_ability[0].video_format));
        DEBUGMSG(ZONE_INFO, ("VI:0 mode_type=%d\n", g_vi_cap_ability[0].mode_type));
        DEBUGMSG(ZONE_INFO, ("VI:0 current_fps=%d\n", g_vi_cap_ability[0].current_fps));

        DEBUGMSG(ZONE_INFO, ("VI:1 input_type=%d\n", g_vi_cap_ability[1].input_type));
        DEBUGMSG(ZONE_INFO, ("VI:1 dev_type=%d\n", g_vi_cap_ability[1].dev_type));
        DEBUGMSG(ZONE_INFO, ("VI:1 frame_rate=%d\n", g_vi_cap_ability[1].frame_rate));
        DEBUGMSG(ZONE_INFO, ("VI:1 video_format=%d\n", g_vi_cap_ability[1].video_format));
        DEBUGMSG(ZONE_INFO, ("VI:1 mode_type=%d\n", g_vi_cap_ability[1].mode_type));
        DEBUGMSG(ZONE_INFO, ("VI:1 current_fps=%d\n", g_vi_cap_ability[1].current_fps));
    }
#endif
    return g_vi_cap_ability;
}

static inline int venc_is_video_capture_interlaced(int stream)
{
    int intlc_scan = 0, interlaced_vi = 0;
    sgks_vi_src_capability_s *current_vi_cap_ability = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    current_vi_cap_ability = venc_get_vi_capability();
    if(current_vi_cap_ability == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: get current vi cap ability fail %s\n", __FUNCTION__));
        return NULL;
    }
    interlaced_vi = (current_vi_cap_ability->video_format == SGKS_VIDEO_FORMAT_INTERLACE);
    intlc_scan = mpi->system_source_buff[pMpiVencHandle->encodeStreams[stream].format.source].format.intlc_scan;
    return (interlaced_vi || ((!interlaced_vi) && (intlc_scan == INTLC_ON)));
}


static int venc_calc_encode_frame_rate(u32 vi_frame_rate, u32 interlaced, u32 deintlc_option,
                                       u32 multiplication_factor, u32 division_factor,u32 *dsp_encode_frame_rate)
{
    u8    scan_format = 0;
    u8    den_encode_frame_rate = 0;
    u32   custom_encoder_frame_rate =0;

    switch(vi_frame_rate)
    {
        case SGKS_VIDEO_FPS_59_94:
            den_encode_frame_rate = 1;

            if(interlaced)
            {
                custom_encoder_frame_rate = 30000;        // 59.94i --> 29.97p
            }
            else
            {
                custom_encoder_frame_rate = 60000;        // 59.94p
            }
            break;

        case SGKS_VIDEO_FPS_50:
            den_encode_frame_rate = 0;

            if(interlaced)
            {
                custom_encoder_frame_rate = 25000;        // 50i --> 25p
            }
            else
            {
                custom_encoder_frame_rate = 50000;        // 50p
            }
            break;

        case SGKS_VIDEO_FPS_29_97:
            den_encode_frame_rate = 1;
            custom_encoder_frame_rate = 30000;
            break;

        case SGKS_VIDEO_FPS_23_976:
            den_encode_frame_rate = 1;
            custom_encoder_frame_rate = 24000;
            break;

        case SGKS_VIDEO_FPS_12_5:
            custom_encoder_frame_rate = 12500;
            break;

        case SGKS_VIDEO_FPS_6_25:
            custom_encoder_frame_rate = 6250;
            break;

        case SGKS_VIDEO_FPS_3_125:
            custom_encoder_frame_rate = 3125;
            break;

        case SGKS_VIDEO_FPS_7_5:
            custom_encoder_frame_rate = 7500;
            break;

        case SGKS_VIDEO_FPS_3_75:
            custom_encoder_frame_rate = 3750;
            break;

        default:
            custom_encoder_frame_rate = DIV_ROUND(512000000, vi_frame_rate) * 1000;
            break;
    }

    scan_format = (interlaced) & (deintlc_option == DEINTLC_OFF);
    custom_encoder_frame_rate = custom_encoder_frame_rate * multiplication_factor / division_factor;
    *dsp_encode_frame_rate = ((scan_format << VENC_SCAN_FORMAT_BIT_SHIFT) |
                              (den_encode_frame_rate << VENC_DENOMINATOR_BIT_SHIFT) |
                              custom_encoder_frame_rate);

    //DEBUGMSG(ZONE_INFO, ("vi fps %d\n", vi_frame_rate));
    //DEBUGMSG(ZONE_INFO, ("scan format: %d, den_encode_fps: %d\n", scan_format, den_encode_frame_rate ? 1001 : 1000));
    //DEBUGMSG(ZONE_INFO, ("encode fps %d\n", custom_encoder_frame_rate));

    return SGKS_SUCCESS;
}

static int venc_alloc_jpeg_qt_matrix(void)
{
    int i;
    u32 total_size;
    u8 *msg_buf = NULL;

    total_size = MULTI_STREAM_MAX_NUM * JPEG_QT_SIZE * JPEG_QT_BUFFER_NUM;
    SGKS_MDI_DRV_BUFF(msg_buf);
    g_quant_matrix_addr.size = total_size;
    memcpy(msg_buf, (u8 *)&g_quant_matrix_addr, sizeof(sgks_mdi_mem_s));
    SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_MALLOC, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    memcpy((u8 *)&g_quant_matrix_addr, msg_buf, sizeof(sgks_mdi_mem_s));
    memset(g_quant_matrix_addr.user_addr, 0x00, total_size);

    // use buffer 0 initially
    for(i = 0; i < MULTI_STREAM_MAX_NUM; ++i)
    {
        pMpiVencHandle->encodeStreams[i].config->jpeg_encode_config.jpeg_quant_matrix = g_quant_matrix_addr.user_addr + i * JPEG_QT_SIZE;
    }
    return SGKS_SUCCESS;
}

static void venc_init_jpeg_dqt(u8 *qtbl, int quality)
{
    static const u8 std_jpeg_qt[128] =
    {
        0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E,
        0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
        0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
        0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33,
        0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44,
        0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57,
        0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71,
        0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63,
        0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2F, 0x1A,
        0x1A, 0x2F, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
        0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
    };
    int i, scale, temp;
    scale = (quality < 50) ? (5000 / quality) : (200 - quality * 2);

    for(i = 0; i < 128; i++)
    {
        temp = ((long) std_jpeg_qt[i] * scale + 50L) / 100L;

        /* limit the values to the valid range */
        if(temp <= 0L)
        {
            temp = 1L;
        }
        else if(temp > 255L)
        {
            temp = 255L;        /* max quantizer needed for baseline */
        }

        qtbl[i] = temp;
    }
}

static void venc_init_stream_jpeg_dqt(int stream, int quality)
{
    // default index is 0
    int buff_size = 0;
    int curr_idx = 0;
    static int qtbl_idx[MULTI_STREAM_MAX_NUM];
    sgks_venc_mjpeg_config_s *pMjpegConfig = &(pMpiVencHandle->encodeStreams[stream].config->jpeg_encode_config);

    curr_idx = qtbl_idx[stream];
    buff_size = MULTI_STREAM_MAX_NUM * JPEG_QT_SIZE;
    pMjpegConfig->jpeg_quant_matrix = g_quant_matrix_addr.user_addr + curr_idx * buff_size + stream * JPEG_QT_SIZE;
    venc_init_jpeg_dqt(pMjpegConfig->jpeg_quant_matrix, quality);
    qtbl_idx[stream] = (curr_idx + 1) % JPEG_QT_BUFFER_NUM;
}

static inline int venc_is_video_encode_interlaced(int stream)
{
    int deintlc_option, interlaced_vi, intlc_scan;
    sgks_source_buffer_format_ex_t *format = NULL;
    u8 source_id;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    source_id= pMpiVencHandle->encodeStreams[stream].format.source;
    format = &mpi->system_source_buff[source_id].format;

    interlaced_vi = (venc_get_vi_capability()->video_format == SGKS_VIDEO_FORMAT_INTERLACE);
    deintlc_option = format->deintlc_for_intlc_vi;
    intlc_scan = format->intlc_scan;
    //if it's interlaced VI, and field encoding; or it's progressive VI, and encode into interlaced
    return ((interlaced_vi && (deintlc_option == DEINTLC_OFF)) || ((!interlaced_vi) && (intlc_scan == INTLC_ON)));
}

static int venc_change_framerate_factor(sgks_mpi_venc_change_framerate_factor_s *pFramerateFactor)
{

    sgks_mpi_venc_change_framerate_factor_s change_frame_rate;
    int stream_id = 0;
    int ret = SGKS_SUCCESS;
    u32 flags = 0;

    memcpy(&change_frame_rate, pFramerateFactor, sizeof(change_frame_rate));
    stream_id = change_frame_rate.id;
    if(venc_check_framerate_factor_ex(&change_frame_rate) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: param error %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }
    g_encode_config[stream_id].frame_rate_division_factor = change_frame_rate.ratio_denominator;
    g_encode_config[stream_id].frame_rate_multiplication_factor = change_frame_rate.ratio_numerator;
    if(venc_is_stream_in_encoding(stream_id))
    {
        if(venc_check_encode_resource_limit(0, venc_get_vi_capability()->frame_rate) < 0)
        {
            DEBUGMSG(ZONE_ERROR, ("cannot change frame factor, system resource not enough \n"));
            return SGKS_ERR_VENC_DEVICEERR;
        }
        flags = VENC_REALTIME_PARAM_CUSTOM_FRAME_RATE_BIT | VENC_REALTIME_PARAM_CUSTOM_VI_FPS_BIT;
        ret = venc_cmd_update_encode_params(stream_id, flags);
    }
    return ret;

}

static int venc_set_encode_fps(u32 idFormat, u32 fpsTime, u32 viFrameRateTime)
{
    u32  ratioNumerator;
    sgks_mpi_venc_change_framerate_factor_s change_fr;

    if(fpsTime < 100)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: param error %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    ratioNumerator = (viFrameRateTime / 100 * 60) / (fpsTime / 100);

    if(ratioNumerator > 60)
    {
        ratioNumerator = 60;
    }

    change_fr.id = idFormat;
    change_fr.ratio_numerator = ratioNumerator;
    change_fr.ratio_denominator = 60;

    return venc_change_framerate_factor(&change_fr);

}

static inline CAPTURE_BUFFER_ID venc_get_capture_buffer_id(u8 source_buffer_id)
{
    CAPTURE_BUFFER_ID capBuffId;

    switch(source_buffer_id)
    {
        case 1:
            capBuffId = PREVIEW_C_BUFFER_ID;
            break;
        case 2:
            capBuffId = PREVIEW_B_BUFFER_ID;
            break;
        case 3:
            capBuffId = PREVIEW_A_BUFFER_ID;
            break;
        case 0:
        default:
            capBuffId = MAIN_BUFFER_ID;
            break;
    }
    return capBuffId;
}

static int venc_get_qp_limit(sgks_venc_change_qp_limit_s  *pVencQP)
{
    int stream_id = 0;
    sgks_venc_change_qp_limit_s qp_limit;

    stream_id = pVencQP->id;
    sgks_venc_h264_config_s *h264 = &(pMpiVencHandle->encodeStreams[stream_id].config->h264_encode_config);
    pVencQP->qp_max_on_I = h264->qp_max_on_I;
    pVencQP->qp_max_on_P = h264->qp_max_on_P;
    pVencQP->qp_max_on_B = h264->qp_max_on_B;
    pVencQP->qp_min_on_I = h264->qp_min_on_I;
    pVencQP->qp_min_on_P = h264->qp_min_on_P;
    pVencQP->qp_min_on_B = h264->qp_min_on_B;
    pVencQP->adapt_qp = h264->adapt_qp;
    pVencQP->i_qp_reduce = h264->i_qp_reduce;
    pVencQP->p_qp_reduce = h264->p_qp_reduce;
    pVencQP->skip_flag = h264->skip_flag;
    //pVencQP->id = (1 << stream_id);

    return SGKS_SUCCESS;
}

static int venc_change_qp_limit(sgks_venc_change_qp_limit_s *pVencQP)
{
#define H264_AQP_MAX    4
#define H264_I_QP_REDUCE_MAX    10
#define H264_I_QP_REDUCE_MIN    1
#define H264_P_QP_REDUCE_MAX    5
#define H264_P_QP_REDUCE_MIN    1
    sgks_venc_h264_config_s *h264 = NULL;
    int stream_id = 0;

    stream_id = pVencQP->id;
    //validte qp limit range
    if((pVencQP->qp_max_on_I > VENC_H264_QP_MAX) ||
       (pVencQP->qp_min_on_I > pVencQP->qp_max_on_I) ||
       (pVencQP->qp_max_on_P > VENC_H264_QP_MAX) ||
       (pVencQP->qp_min_on_P > pVencQP->qp_max_on_P) ||
       (pVencQP->qp_max_on_B > VENC_H264_QP_MAX) ||
       (pVencQP->qp_min_on_B > pVencQP->qp_max_on_B) ||
       (pVencQP->adapt_qp > H264_AQP_MAX) ||
       (pVencQP->i_qp_reduce < H264_I_QP_REDUCE_MIN) ||
       (pVencQP->i_qp_reduce > H264_I_QP_REDUCE_MAX) ||
       (pVencQP->p_qp_reduce < H264_P_QP_REDUCE_MIN) ||
       (pVencQP->p_qp_reduce > H264_P_QP_REDUCE_MAX))
    {
        DEBUGMSG(ZONE_ERROR, ("qp_limit range invalid \n"));
        return SGKS_ERR_VENC_PARAMERR;
    }

    h264 = &pMpiVencHandle->encodeStreams[stream_id].config->h264_encode_config;
    h264->qp_min_on_I = pVencQP->qp_min_on_I;
    h264->qp_max_on_I = pVencQP->qp_max_on_I;
    h264->qp_min_on_P = pVencQP->qp_min_on_P;
    h264->qp_max_on_P = pVencQP->qp_max_on_P;
    h264->qp_min_on_B = pVencQP->qp_min_on_B;
    h264->qp_max_on_B = pVencQP->qp_max_on_B;
    h264->adapt_qp = pVencQP->adapt_qp;
    h264->i_qp_reduce = pVencQP->i_qp_reduce;
    h264->p_qp_reduce = pVencQP->p_qp_reduce;
    h264->skip_flag = pVencQP->skip_flag;
    h264->qp_min_on_I = 1;
    h264->qp_min_on_P = 1;
    h264->qp_min_on_B = 1;

    //stream is in encoding state, changing frame rate on the fly
    if(venc_is_stream_in_h264_encoding(stream_id))
    {
        if(venc_cmd_update_encode_params(stream_id, VENC_REALTIME_PARAM_QP_LIMIT_BIT) < 0)
        {
            return SGKS_ERR_VENC_SENDCMDFAIL;
        }
    }

    return SGKS_SUCCESS;
}

static inline void venc_buffer_size_roundup(int intlc_vi_intlc_enc, int encode_type,
        u16 origin_width, u16 origin_height,
        u16 *roundup_width, u16 *roundup_height)
{
    u16 round_h;

    if(intlc_vi_intlc_enc)
    {
        round_h = 32;
    }
    else
    {
        round_h    = 16;
    }

    if(encode_type == SGKS_ENCODE_H264)
    {
        *roundup_width = ROUND_UP(origin_width, 16);
        *roundup_height = ROUND_UP(origin_height, round_h);
    }
    else
    {
        *roundup_width = origin_width;
        *roundup_height = origin_height;
    }
}

static inline void venc_get_pic_info_in_h264(int stream, sgks_venc_h264_config_s *config)
{
    config->pic_info.ar_x = 0;
    config->pic_info.ar_y = 0;
    config->pic_info.frame_mode = 1;
    config->pic_info.width = pMpiVencHandle->encodeStreams[stream].format.encode_width;
    config->pic_info.height = pMpiVencHandle->encodeStreams[stream].format.encode_height;

    u8 tmp = sgks_mpi_vo_FpsFormatToVfr(venc_get_vi_capability()->frame_rate, venc_get_vi_capability()->video_format);
    if(tmp < 2)
    {
        config->pic_info.rate = 3003;
    }
    else if(tmp < 4)
    {
        config->pic_info.rate = 1501;
    }
    else
    {
        config->pic_info.rate = 90000 / tmp;
    }

    config->pic_info.scale = 90000;

}

static int venc_set_dptz_control_param(sgks_venc_dptz_param_s *pVencDptz)
{
    sgks_venc_digital_zoom_s  dptz;
    int ret = SGKS_SUCCESS;
    sgks_venc_digital_zoom2_s dptz2;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    if(pVencDptz->channelId == VENC_CHANNEL_1)
    {
        /*get previous dptz parameter*/
        memcpy(&dptz, &g_digital_zoom, sizeof(g_digital_zoom));

        venc_calc_dptz_i_param(pVencDptz, &dptz);
        ret = venc_set_digital_zoom(&dptz);
        if(SGKS_SUCCESS != ret)
        {
            DEBUGMSG(ZONE_ERROR, ("set digital zoom failed.\n"));
            return ret;
        }
    }
    else
    {
        /*get previous dptz parameter*/
        dptz2.source = pVencDptz->channelId;
        if((dptz2.source < SGKS_ENCODE_SUB_SOURCE_BUFFER_FIRST) || (dptz2.source >= SGKS_ENCODE_SUB_SOURCE_BUFFER_LAST))
        {
            DEBUGMSG(ZONE_ERROR, ("Invalid source buffer id [%d], out of range [0~3].\n", dptz2.source));
            return SGKS_ERR_VENC_PARAMERR;
        }

        dptz2.input_width =  mpi->system_source_buff[dptz2.source].format.input_width;
        dptz2.input_height = mpi->system_source_buff[dptz2.source].format.input_height;
        dptz2.input_offset_x = mpi->system_source_buff[dptz2.source].format.input_offset_x;
        dptz2.input_offset_y = mpi->system_source_buff[dptz2.source].format.input_offset_y;

        ret = venc_calc_dptz_ii_param(pVencDptz, &dptz2);
        if(SGKS_SUCCESS != ret)
        {
            DEBUGMSG(ZONE_ERROR, ("Calculate DPTZ II parameters failed\n"));
            return ret;
        }

        ret = venc_set_2nd_digital_zoom_ex(&dptz2);
        if(ret != SGKS_SUCCESS)
        {
            DEBUGMSG(ZONE_ERROR, ("set 2nd digital zoom failed.\n"));
            return ret;
        }
    }

    return ret;
}


static int venc_zoom_to_max_fov_keep_as(u32 idFormat)
{
    u32 i;
    sgks_venc_dptz_param_s dptz;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    memset(&dptz, 0, sizeof(sgks_venc_dptz_param_s));

    for(i = 0; i < VENC_STREAM_NUM; ++i)
    {
        if(idFormat & (1 << i))
        {
            dptz.channelId = pMpiVencHandle->encodeStreams[i].format.source;
            venc_set_dptz_control_param(&dptz);
        }
    }

    return SGKS_SUCCESS;
}
static int venc_calc_dptz_i_param(sgks_venc_dptz_param_s *pVencDptz, sgks_venc_digital_zoom_s *pDptz)
{
    const s32 MAX_ZOOM_FACTOR_Y = (4 << 16);
    const s32 CENTER_OFFSET_Y_MARGIN = 4;
    s32 viW, viH;
    s32 maxWindowFactor, maxZoomFactor, factorX, factorY;
    s32 x, y, maxX, maxY;
    s32 zoomOutWidth, zoomOutHeight;
    sgks_vi_src_capability_s *current_vi_cap_ability = NULL;

    sgks_source_buffer_format_ex_t *pMainBufFormat = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    current_vi_cap_ability = venc_get_vi_capability();

    //Note: The api to get vi width and height is not create.
    viW = SGKS_VIDEO_MODE_GET_WIDTH(current_vi_cap_ability->current_vi_mode);
    viH = SGKS_VIDEO_MODE_GET_HEIGTH(current_vi_cap_ability->current_vi_mode);

    pMainBufFormat = &(mpi->system_source_buff[0].format);
    if(pVencDptz->zoomFactor == 0)
    {
        /*restore to 1X center view*/
        factorY = (pMainBufFormat->height << 16) / ROUND_UP(viH - 3, 4);
        factorX = factorY;
        x = y = 0;
    }
    else
    {
        maxWindowFactor = viH * 100 / pMainBufFormat->height;
        maxZoomFactor = MAX_ZOOM_IN_MAIN_BUFFER;
        factorY = (pVencDptz->zoomFactor - 1) * (maxZoomFactor - 100) / MAX_ZOOM_STEPS + 100;
        factorY = maxWindowFactor * 100 / factorY;
        zoomOutWidth  = ROUND_UP(factorY * pMainBufFormat->width / 100, 4);
        zoomOutHeight = ROUND_UP(factorY * pMainBufFormat->height / 100, 4);
        factorX = (pMainBufFormat->width << 16) / zoomOutWidth;
        factorY = (pMainBufFormat->width << 16) / zoomOutHeight;
        x = ((int)pDptz->center_offset_x / 65536) + pVencDptz->offsetX * zoomOutWidth / 1000;
        y = ((int)pDptz->center_offset_y / 65536) + pVencDptz->offsetY * zoomOutHeight / 1000;
        maxX = viW / 2 - zoomOutWidth / 2;
        maxY = viH / 2 - zoomOutHeight / 2;

        if(factorY >= MAX_ZOOM_FACTOR_Y)
        {
            maxY -= CENTER_OFFSET_Y_MARGIN;
        }

        if(x < -maxX)
        {
            x = -maxX;
        }

        if(x > maxX)
        {
            x = maxX;
        }

        x <<= 16;

        if(y < -maxY)
        {
            y = -maxY;
        }

        if(y > maxY)
        {
            y = maxY;
        }

        y <<= 16;
    }

    pDptz->zoom_factor_x = factorX;
    pDptz->zoom_factor_y = factorY;
    pDptz->center_offset_x = x;
    pDptz->center_offset_y = y;

    return SGKS_SUCCESS;
}

static int venc_calc_dptz_ii_param(sgks_venc_dptz_param_s *pVencDptz, sgks_venc_digital_zoom2_s *pDptz)
{
    s32 x, y;
    s32 maxZoomFactor, maxWindowFactor, zoomFactor;
    s32 zoomOutWidth, zoomOutHeight;
    s32 maxHeightFactor, maxWidthFactor;
    sgks_source_buffer_format_ex_t *mainBufFormat = NULL;
    sgks_source_buffer_format_ex_t *targetBufFormat = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    mainBufFormat = &(mpi->system_source_buff[VENC_CHANNEL_1].format);
    targetBufFormat = &(mpi->system_source_buff[pVencDptz->channelId].format);

    if(targetBufFormat->height == 0 || targetBufFormat->width == 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    maxHeightFactor = (mainBufFormat->height * 100) / targetBufFormat->height;
    maxWidthFactor  = (mainBufFormat->width * 100) / targetBufFormat->width;

    if(pVencDptz->zoomFactor == 0)
    {
        // restore to 1X center view
        if(maxHeightFactor <= maxWidthFactor)
        {
            zoomFactor = maxHeightFactor;
            zoomOutWidth  = zoomFactor * targetBufFormat->width / 100;
            zoomOutHeight = mainBufFormat->height;
            x = (mainBufFormat->width - zoomOutWidth) / 2;
            y = 0;
        }
        else
        {
            zoomFactor = maxWidthFactor;
            zoomOutWidth  = mainBufFormat->width;
            zoomOutHeight = zoomFactor * targetBufFormat->height / 100;
            x = 0;
            y = (mainBufFormat->height - zoomOutHeight) / 2;
        }
    }
    else
    {
        maxWindowFactor = maxHeightFactor > maxWidthFactor ? maxWidthFactor : maxHeightFactor;

        if(pVencDptz->channelId == VENC_CHANNEL_2)
        {
            maxZoomFactor = maxWindowFactor;
        }
        else
        {
            maxZoomFactor = MAX_ZOOM_IN_PREVIEW_A_B;
        }

        zoomFactor = (pVencDptz->zoomFactor - 1) * (maxZoomFactor - 100) / MAX_ZOOM_STEPS + 100;
        zoomFactor = maxWindowFactor * 100 / zoomFactor;
        zoomOutWidth  = zoomFactor * targetBufFormat->width / 100;
        zoomOutHeight = zoomFactor * targetBufFormat->height / 100;
        x = pDptz->input_offset_x + pVencDptz->offsetX * zoomOutWidth / 1000;
        y = pDptz->input_offset_y + pVencDptz->offsetY * zoomOutHeight / 1000;

        if(x + zoomOutWidth > mainBufFormat->width)
        {
            x = mainBufFormat->width - zoomOutWidth;
        }

        x = (x > 0) ? x : 0;

        if(y + zoomOutHeight > mainBufFormat->height)
        {
            y = mainBufFormat->height - zoomOutHeight;
        }

        y = (y > 0) ? y : 0;
    }

    pDptz->source = pVencDptz->channelId;
    pDptz->input_width = zoomOutWidth & (~0x1);
    pDptz->input_height = zoomOutHeight & (~0x3);
    pDptz->input_offset_x = x & (~0x1);
    pDptz->input_offset_y = y & (~0x3);

    return SGKS_SUCCESS;
}


static inline int venc_calc_max_num_cap_sources(void)
{
    const int     CAP_SOURCES_IN_MAX = 3;
    int max_num_cap_sources = 2;    //minimum cap sources
    sgks_mpi_manager_s *mpi =NULL;
    mpi = mpi_get_managerHanle();
    if(mpi == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: mpi is null %s\n", __FUNCTION__));
        return SGKS_ERR_SYS_INITFAIL;
    }

    if((mpi->system_source_buff[2].type == SGKS_SOURCE_BUFFER_TYPE_ENCODE) && (mpi->system_resource.third_source_buffer_max_width != 0))
    {
        max_num_cap_sources++;
    }

    if((mpi->system_source_buff[3].type == SGKS_SOURCE_BUFFER_TYPE_ENCODE) && (mpi->system_resource.fourth_source_buffer_max_width != 0))
    {
        max_num_cap_sources++;
    }

    if(max_num_cap_sources > CAP_SOURCES_IN_MAX)
    {
        max_num_cap_sources = CAP_SOURCES_IN_MAX;
    }

    return max_num_cap_sources;
}

static inline void venc_calc_h264_offset_y(int stream, u16 width_round, u16 height_round, s16 *offset_y)
{
    s16 offset;
    sgks_venc_h264_config_s *config =  &pMpiVencHandle->encodeStreams[stream].config->h264_encode_config;
    sgks_mpi_venc_format_s *format = &pMpiVencHandle->encodeStreams[stream].format;

    if(config->rotate_clockwise && !config->hflip)
    {
        offset = format->encode_y + format->encode_height - width_round;
    }
    else if(!config->rotate_clockwise && config->vflip)
    {
        offset = format->encode_y + format->encode_height - height_round;
    }
    else
    {
        offset = format->encode_y;
    }

    *offset_y = offset;
}

static int venc_calc_quality_model(sgks_venc_h264_config_s *config)
{
    static u8 lvarr[] = {1, 2, 4, 8};
    int lv = -1;
    int i;

    if(config->M == 0 || config->M > 8)
    {
        DEBUGMSG(ZONE_ERROR, ("bad M %d\n", config->M));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(config->N == 0 || (config->N % config->M) != 0)
    {
        DEBUGMSG(ZONE_ERROR, ("bad N %d\n", config->N));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(config->idr_interval == 0)
    {
        DEBUGMSG(ZONE_ERROR,("bad idr_interval %d\n", config->idr_interval));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(config->gop_model == MEDIA_GOP_SIMPLE)
    {
        return SGKS_SUCCESS;   // simple GOP
    }
    else if(config->gop_model == MEDIA_GOP_NON_REF_P)
    {
        return NON_REF_P_GOP;  //GOP structure for temporal SVC
    }
    else if(config->gop_model == MEDIA_GOP_HI_P)
    {
        return HI_P_GOP;  // GOP structure for 2 level hierarchical SVC
    }

    // MEDIA_GOP_ADVANCED, use hierarchical
    for(i = 0; i < ARRAY_SIZE(lvarr); i++)
    {
        if(config->M == lvarr[i])
        {
            lv = i + 1;
            break;
        }
    }

    if(lv < 0)
    {
        return lv;
    }

    return (lv << 5) | 4;
}

static int venc_get_session_id(int stream, u32 *pSessionID)
{
    u8 *msg_buf = NULL;
    sgks_mdi_session_s session;

    session.streamId = stream;
    session.session = pSessionID;

    SGKS_MDI_DRV_BUFF(msg_buf);
    memcpy(msg_buf, (u8 *)&session, sizeof(sgks_mdi_session_s));
    SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_GET_SESSION_ID, 0, sizeof(sgks_mdi_session_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
}

static int venc_check_framerate_factor_ex(sgks_mpi_venc_change_framerate_factor_s *framerate)
{
    u32 real_fps = venc_get_vi_capability()->frame_rate;

    if(framerate->ratio_numerator > framerate->ratio_denominator)
    {
        DEBUGMSG(ZONE_ERROR, ("Can't change frame rate by %u/%u, faster than VI frame rate\n",
                              framerate->ratio_numerator, framerate->ratio_denominator));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if((framerate->ratio_numerator > 255) || (framerate->ratio_denominator > 255))
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(framerate->ratio_numerator != 0 && framerate->ratio_denominator != 0)
    {
        real_fps = real_fps * framerate->ratio_numerator / framerate->ratio_denominator;

        if(real_fps == 0)
        {
            DEBUGMSG(ZONE_ERROR, ("Can't change frame rate less than 1fps.\n"));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }

    return SGKS_SUCCESS;
}

static int venc_check_encode_resource_limit(u32 encode_stream_id, u32 vi_fps)
{
    int i, interlaced;
    u32 system_load = 0, load;
    u32 vi_frame_rate = DIV_ROUND(512000000, vi_fps);

    for(i = 0; i < MULTI_STREAM_MAX_NUM; i++)
    {
        if(venc_is_stream_in_encoding(i) || (encode_stream_id & (1 << i)))
        {
            load = ROUND_UP(pMpiVencHandle->encodeStreams[i].format.encode_width, 16) / 16 *
                   ROUND_UP(pMpiVencHandle->encodeStreams[i].format.encode_height, 16) / 16 *
                   vi_frame_rate *
                   g_encode_config[i].frame_rate_multiplication_factor /
                   g_encode_config[i].frame_rate_division_factor;
            interlaced = venc_is_video_encode_interlaced(i);
            system_load += (interlaced == 0 ? load : load / 2);
        }
    }

    return SGKS_SUCCESS;
}

static int venc_check_system_resource_limit(sgks_system_resource_setup_ex_t *resource)
{
    int i;
    sgks_source_buffer_property_ex_t *property = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    // check CAVLC maximum bitrate
    if(resource->cavlc_max_bitrate > MEDIA_MAX_CAVLC_BITRATE)
    {
        DEBUGMSG(ZONE_INFO, ("Setting: cavlc_max_bitrate [%d] is larger than system"
                             " limit [%d], restore to [%d]",
                             resource->cavlc_max_bitrate, MEDIA_MAX_CAVLC_BITRATE,
                             MEDIA_MAX_CAVLC_BITRATE));

        resource->cavlc_max_bitrate = MEDIA_MAX_CAVLC_BITRATE;
    }

    // check system resource with buffer property
    property = &mpi->system_source_buff[SGKS_ENCODE_SOURCE_MAIN_BUFFER].property;
    if((resource->main_source_buffer_max_width > property->max_width) ||
       (resource->main_source_buffer_max_height > property->max_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Error:Max main source buffer %dx%d is larger than hard limit %dx%d. %s\n",
                              resource->main_source_buffer_max_width,
                              resource->main_source_buffer_max_height,
                              property->max_width, property->max_height,
                              __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    property = &mpi->system_source_buff[SGKS_ENCODE_SOURCE_THIRD_BUFFER].property;
    if((resource->third_source_buffer_max_width > property->max_width) ||
       (resource->third_source_buffer_max_height > property->max_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Max third source buffer %dx%d is larger than hard limit %dx%d. %s\n",
                              resource->third_source_buffer_max_width,
                              resource->third_source_buffer_max_height,
                              property->max_width, property->max_height,
                              __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    property = &mpi->system_source_buff[SGKS_ENCODE_SOURCE_FOURTH_BUFFER].property;
    if((resource->fourth_source_buffer_max_width > property->max_width) ||
       (resource->fourth_source_buffer_max_height > property->max_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Max fourth source buffer %dx%d is larger than hard limit %dx%d.\n",
                              resource->fourth_source_buffer_max_width,
                              resource->fourth_source_buffer_max_height,
                              property->max_width, property->max_height,
                              __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check max GOP M resource limitation
    if(resource->stream_max_GOP_M[0] > MAX_REF_FRAME_INTVL)
    {
        DEBUGMSG(ZONE_ERROR, ("Stream A cannot have max GOP M [%d] larger than %d.%s\n",
                              resource->stream_max_GOP_M[0], MAX_REF_FRAME_INTVL,
                              __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    for(i = 1; i < MULTI_STREAM_MAX_NUM; ++i)
    {
        if(resource->stream_max_GOP_M[i] > 1)
        {
            DEBUGMSG(ZONE_ERROR, ("Stream %c cannot have B frames with M [%d] larger than 1. %s\n",
                                  'A' + i, resource->stream_max_GOP_M[i], __FUNCTION__));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }
    // check oversampling disable
    if(resource->oversampling_disable > 1)
    {
        DEBUGMSG(ZONE_ERROR, ("Oversampling disable flag can only be [0|1].%s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check hd sdi mode
    if(resource->hd_sdi_mode > 1)
    {
        DEBUGMSG(ZONE_ERROR, ("hd_sdi_mode flag can only be [0|1].%s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }
    return SGKS_SUCCESS;
}

static int venc_check_system_source_buffer_limit(u32 source_buffer_id, u32 buffer_width, u32 buffer_height)
{
    u32 max_width, max_height;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    switch(source_buffer_id)
    {
        case SGKS_ENCODE_SOURCE_MAIN_BUFFER:
            max_width = mpi->system_resource.main_source_buffer_max_width;
            max_height = mpi->system_resource.main_source_buffer_max_height;
            break;
        case SGKS_ENCODE_SOURCE_SECOND_BUFFER:
            max_width = mpi->system_resource.second_source_buffer_max_width;
            max_height = mpi->system_resource.second_source_buffer_max_height;
            break;
        case SGKS_ENCODE_SOURCE_THIRD_BUFFER:
            max_width = mpi->system_resource.third_source_buffer_max_width;
            max_height = mpi->system_resource.third_source_buffer_max_height;
            break;
        case SGKS_ENCODE_SOURCE_FOURTH_BUFFER:
            max_width = mpi->system_resource.fourth_source_buffer_max_width;
            max_height = mpi->system_resource.fourth_source_buffer_max_height;
            break;
        default:
            DEBUGMSG(ZONE_ERROR, ("Invalid source buffer id [%d].\n", source_buffer_id));
            return SGKS_ERR_VENC_PARAMERR;
            break;
    }

    if((buffer_width > max_width) || (buffer_height > max_height))
    {
        DEBUGMSG(ZONE_ERROR, ("New source buffer size %dx%d is larger than the supported max %dx%d.\n",
                              buffer_width, buffer_height, max_width, max_height));
        return SGKS_ERR_VENC_PARAMERR;
    }

    return SGKS_SUCCESS;
}

static int venc_check_system_source_buffer_property(u32 source_buffer_id,u32 buffer_width,
        u32 buffer_height, u32 input_width, u32 input_height)
{

    sgks_mpi_manager_s *mpi = NULL;
    sgks_source_buffer_type_ex_t type;
    sgks_source_buffer_property_ex_t *pSystemBufferproperty =NULL;

    mpi = mpi_get_managerHanle();
    type = mpi->system_source_buff[source_buffer_id].type;
    pSystemBufferproperty = &(mpi->system_source_buff[source_buffer_id].property);

    if((buffer_width > pSystemBufferproperty->max_width) || (buffer_height > pSystemBufferproperty->max_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] size %dx%d too big, can only be up to %dx%d.\n",
                              source_buffer_id, buffer_width, buffer_height,
                              pSystemBufferproperty->max_width, pSystemBufferproperty->max_height));

        goto error_exit;
    }

    if(SGKS_SOURCE_BUFFER_TYPE_ENCODE == type)
    {
        if(((pSystemBufferproperty->max_zoom_out_factor * buffer_width) < input_width) ||
           ((pSystemBufferproperty->max_zoom_out_factor * buffer_height) < input_height))
        {
            DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] downscaled from %dx%d to %dx%d"
                                  ", out of the max zoom out factor [%d].\n", source_buffer_id,
                                  input_width, input_height, buffer_width, buffer_height,
                                  pSystemBufferproperty->max_zoom_out_factor));
            goto error_exit;
        }

        if(((pSystemBufferproperty->max_zoom_in_factor * input_width) < buffer_width) ||
           ((pSystemBufferproperty->max_zoom_in_factor * input_height) < buffer_height))
        {
            DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] upscaled from %dx%d to %dx%d"
                                  ", out of the max zoom in factor [%d].\n", source_buffer_id,
                                  input_width, input_height, buffer_width, buffer_height,
                                  pSystemBufferproperty->max_zoom_in_factor));
            goto error_exit;
        }
    }

    return SGKS_SUCCESS;
error_exit:
    DEBUGMSG(ZONE_ERROR, ("Please refer to documents to check the supported zoom factor.\n"));
    return SGKS_ERR_VENC_PARAMERR;
}


static int venc_check_system_main_source_buffer_config(sgks_source_buffer_format_all_s *format, int *specify)
{
    int main_deintlc = format->main_deintlc_for_intlc_vi;
    int second_deintlcc = format->second_deintlc_for_intlc_vi;
    sgks_source_buffer_ex_t *pSystemSourceBuffer = NULL;
    sgks_system_resource_setup_ex_t *pSystemResource = NULL;
    u32 sys_status = 0;

    sgks_vi_src_capability_s *current_vi_info = venc_get_vi_capability();
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    if((format->main_width & 0xF) || (format->main_height & 0x1))
    {
        DEBUGMSG(ZONE_ERROR, ("Main source buffer width must be multiple of 16 and height must be multiple of 2.\n"));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // error if main buffer resolution higher than VI
    if((format->main_width > current_vi_info->cap_width) || (format->main_height > current_vi_info->cap_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Main source buffer size %dx%d is bigger than VI %dx%d.\n",
                              format->main_width, format->main_height,
                              current_vi_info->cap_width, current_vi_info->cap_height));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // error if main buffer resolution higher than max size
    pSystemResource = &mpi->system_resource;

    if((format->main_width > pSystemResource->main_source_buffer_max_width) ||
       (format->main_height > pSystemResource->main_source_buffer_max_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Main source buffer size %dx%d is bigger than max %dx%d.\n",
                              format->main_width, format->main_height,
                              pSystemResource->main_source_buffer_max_width,
                              pSystemResource->main_source_buffer_max_height));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check main buffer property
    if(venc_check_system_source_buffer_property(SGKS_ENCODE_SOURCE_MAIN_BUFFER,
            format->main_width, format->main_height, current_vi_info->cap_width,
            current_vi_info->cap_height) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    // error if input window is larger than main source buffer
    if((format->second_input_width > format->main_width) ||
       (format->second_input_height > format->main_height) ||
       (format->third_input_width > format->main_width) ||
       (format->third_input_height > format->main_height) ||
       (format->fourth_input_width > format->main_width) ||
       (format->fourth_input_height > format->main_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Input window of second, third or fourth source buffer cannot be"
                              " larger than main source buffer %dx%d.\n",
                              format->main_width, format->main_height));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check de-interlace option of source buffer
    if(current_vi_info->video_format == SGKS_VIDEO_FORMAT_INTERLACE)
    {
        if(main_deintlc > DEINTLC_WEAVE_MODE)
        {
            DEBUGMSG(ZONE_ERROR, ("Invalid de-interlaced [%d] of main, cannot be larger than %d.\n",
                                  main_deintlc, DEINTLC_WEAVE_MODE));
            return SGKS_ERR_VENC_PARAMERR;
        }

        if((main_deintlc != DEINTLC_BOB_MODE) && (second_deintlcc == DEINTLC_BOB_MODE))
        {
            if(format->second_height >= format->main_height)
            {
                DEBUGMSG(ZONE_ERROR, ("Main buffer is NOT BOB and second is BOB,"
                                      " 2nd buffer size must be smaller than main.\n"));
                return SGKS_ERR_VENC_PARAMERR;
            }
        }
    }
    else
    {
        if(main_deintlc != DEINTLC_OFF)
        {
            DEBUGMSG(ZONE_ERROR, ("Progressive VI: main buffer deintlc [%d] must be 0!\n", main_deintlc));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }

    // error if main buffer is changed in NON-IDLE state
    pSystemSourceBuffer = &(mpi->system_source_buff[SGKS_ENCODE_SOURCE_MAIN_BUFFER]);
    if((format->main_width != pSystemSourceBuffer->format.width) ||
       (format->main_height != pSystemSourceBuffer->format.height) ||
       (main_deintlc != pSystemSourceBuffer->format.deintlc_for_intlc_vi))
    {
        /* If it's encoding, cannot reconfigure main buffer because all source
         * buffers come from directly/indirectly from main
         */
        sgks_mpi_sys_GetStats(&sys_status);
        if(sys_status != STATE_IDLE)
        {
            DEBUGMSG(ZONE_ERROR, ("Cannot reconfigure main buffer while MEDIA is not in IDLE state!\n"));
            return SGKS_ERR_VENC_PARAMERR;
        }

        if(pSystemSourceBuffer->state == SGKS_SOURCE_BUFFER_STATE_BUSY)
        {
            DEBUGMSG(ZONE_ERROR, ("Cannot reconfigure source buffer while it's used by the encoder.\n"));
            return SGKS_ERR_VENC_PARAMERR;
        }

        if(specify != NULL)
        {
            specify[SGKS_ENCODE_SOURCE_MAIN_BUFFER] = 1;
        }
    }

    return SGKS_SUCCESS;
}

static int venc_check_system_sub_source_buffer_config(u32 source_buffer_id,
        sgks_source_buffer_format_ex_t *source, u32 main_deintlc,
        u32 main_width, u32 main_height, int *specify)
{
    u32 deintlc;
    u32 buffer_width, buffer_height;
    u32 input_width, input_height;
    u32 input_offset_x, input_offset_y;
    sgks_source_buffer_type_ex_t type;
    sgks_source_buffer_state_ex_t state;
    sgks_vi_src_capability_s *current_vi_info = NULL;
    sgks_mpi_manager_s *mpi =NULL;
    sgks_source_buffer_format_ex_t *origin_format = NULL;

    current_vi_info = venc_get_vi_capability();
    mpi = mpi_get_managerHanle();
    type = mpi->system_source_buff[source_buffer_id].type;
    state = mpi->system_source_buff[source_buffer_id].state;

    deintlc = source->deintlc_for_intlc_vi;
    buffer_width = source->width;
    buffer_height = source->height;
    input_width = source->input_width;
    input_height = source->input_height;
    input_offset_x = source->input_offset_x;
    input_offset_y = source->input_offset_y;

    if((buffer_width == 0) || (buffer_height == 0))
    {
        return SGKS_SUCCESS;
    }

    // check source buffer format
    if((buffer_width & 0x1) || (input_width & 0x1) || (input_offset_x & 0x1))
    {
        DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] width %d, input width %d, offset x %d must be even.\n",
                              source_buffer_id, buffer_width, input_width, input_offset_x));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if((buffer_height & 0x3) || (input_height & 0x3) || (input_offset_y & 0x3))
    {
        DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] height %d, input height %d, offset y %d must be multiple of 4.\n",
                              source_buffer_id, buffer_height, input_height, input_offset_y));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check source buffer maximum limit
    if(venc_check_system_source_buffer_limit(source_buffer_id, buffer_width, buffer_height) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check source buffer property
    if(venc_check_system_source_buffer_property(source_buffer_id, buffer_width, buffer_height, input_width, input_height) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check input offset
    if((input_width + input_offset_x > main_width) ||
       (input_height + input_offset_y > main_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] input %dx%d with offset %dx%d is out of main %dx%d!\n",
                              source_buffer_id, input_width, input_height,
                              input_offset_x, input_offset_y, main_width, main_height));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check de-interlace option
    if(current_vi_info->video_format == SGKS_VIDEO_FORMAT_INTERLACE)
    {
        if(deintlc > DEINTLC_WEAVE_MODE)
        {
            DEBUGMSG(ZONE_ERROR, ("Invalid de-interlaced option [%d], cannot be larger than %d.\n",
                                  deintlc, DEINTLC_WEAVE_MODE));
            return SGKS_ERR_VENC_PARAMERR;
        }

        if((type == SGKS_SOURCE_BUFFER_TYPE_ENCODE) &&
           (main_deintlc == DEINTLC_BOB_MODE) &&
           (deintlc != DEINTLC_BOB_MODE))
        {
            DEBUGMSG(ZONE_ERROR, ("De-interlace option: When main is BOB, buffer [%d] must be BOB too.\n",
                                  source_buffer_id));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }
    else
    {
        if(deintlc != DEINTLC_OFF)
        {
            DEBUGMSG(ZONE_ERROR, ("Progressive VI: source buffer [%d] deintlce option must be 0.\n",
                                  source_buffer_id));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }

    // check source buffer state
    origin_format = &mpi->system_source_buff[source_buffer_id].format;
    if((buffer_width != origin_format->width) || (buffer_height != origin_format->height) ||
       (deintlc != origin_format->deintlc_for_intlc_vi))
    {
        if(state == SGKS_SOURCE_BUFFER_STATE_BUSY)
        {
            DEBUGMSG(ZONE_ERROR, ("Cannot change source buffer size while it's used by the encoder.\n"));
            return SGKS_ERR_VENC_PARAMERR;
        }

        if(specify != NULL)
        {
            specify[source_buffer_id] = 1;
        }
    }

    return SGKS_SUCCESS;
}


static int venc_check_system_source_buffer_format_all( sgks_source_buffer_format_all_s *format, int *specify)
{
    sgks_source_buffer_format_ex_t source;
    memset(&source, 0, sizeof(source));

    // check main source buffer config
    if(venc_check_system_main_source_buffer_config(format, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set main source buffer config!\n"));
        goto error_exit;
    }

    // check 2nd source buffer property
    source.width = format->second_width;
    source.height = format->second_height;
    source.input_width = format->second_input_width;
    source.input_height = format->second_input_height;
    source.deintlc_for_intlc_vi = format->second_deintlc_for_intlc_vi;

    if(venc_check_system_sub_source_buffer_config(SGKS_ENCODE_SOURCE_SECOND_BUFFER,
            &source, format->main_deintlc_for_intlc_vi, format->main_width,
            format->main_height, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set second source buffer config!\n"));
        goto error_exit;
    }

    // check 3rd source buffer property
    source.width = format->third_width;
    source.height = format->third_height;
    source.input_width = format->third_input_width;
    source.input_height = format->third_input_height;
    source.deintlc_for_intlc_vi = format->third_deintlc_for_intlc_vi;

    if(venc_check_system_sub_source_buffer_config(SGKS_ENCODE_SOURCE_THIRD_BUFFER,
            &source, format->main_deintlc_for_intlc_vi, format->main_width,
            format->main_height, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set third source buffer config!\n"));
        goto error_exit;
    }

    // check 4th source buffer property
    source.width = format->fourth_width;
    source.height = format->fourth_height;
    source.input_width = format->fourth_input_width;
    source.input_height = format->fourth_input_height;
    source.deintlc_for_intlc_vi = format->fourth_deintlc_for_intlc_vi;

    if(venc_check_system_sub_source_buffer_config(SGKS_ENCODE_SOURCE_FOURTH_BUFFER,&source,
            format->main_deintlc_for_intlc_vi, format->main_width,
            format->main_height, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set fourth source buffer config!\n"));
        goto error_exit;
    }

    return SGKS_SUCCESS;
error_exit:
    DEBUGMSG(ZONE_ERROR, ("Source buffer size: [%dx%d] [%dx%d] [%dx%d] [%dx%d].\n",
                          format->main_width, format->main_height,
                          format->second_width, format->second_height,
                          format->third_width, format->third_height,
                          format->fourth_width, format->fourth_height));
    return SGKS_ERR_VENC_PARAMERR;
}

static int venc_check_system_source_buffer_config_all(sgks_source_buffer_format_all_s *format, int *specify)
{
    sgks_source_buffer_format_ex_t source;
    memset(&source, 0, sizeof(source));

    // check main source buffer config
    if(venc_check_system_main_source_buffer_config(format, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set main source buffer config!\n"));
        goto error_exit;
    }

    // check 2nd source buffer property
    source.width = format->second_width;
    source.height = format->second_height;
    source.input_width = format->second_input_width;
    source.input_height = format->second_input_height;
    source.deintlc_for_intlc_vi = format->second_deintlc_for_intlc_vi;

    if(venc_check_system_sub_source_buffer_config(SGKS_ENCODE_SOURCE_SECOND_BUFFER,
            &source, format->main_deintlc_for_intlc_vi, format->main_width,
            format->main_height, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set second source buffer config!\n"));
        goto error_exit;
    }

    // check 3rd source buffer property
    source.width = format->third_width;
    source.height = format->third_height;
    source.input_width = format->third_input_width;
    source.input_height = format->third_input_height;
    source.deintlc_for_intlc_vi = format->third_deintlc_for_intlc_vi;

    if(venc_check_system_sub_source_buffer_config(SGKS_ENCODE_SOURCE_THIRD_BUFFER,
            &source, format->main_deintlc_for_intlc_vi, format->main_width,
            format->main_height, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set third source buffer config!\n"));
        goto error_exit;
    }

    // check 4th source buffer property
    source.width = format->fourth_width;
    source.height = format->fourth_height;
    source.input_width = format->fourth_input_width;
    source.input_height = format->fourth_input_height;
    source.deintlc_for_intlc_vi = format->fourth_deintlc_for_intlc_vi;

    if(venc_check_system_sub_source_buffer_config(SGKS_ENCODE_SOURCE_FOURTH_BUFFER,
            &source, format->main_deintlc_for_intlc_vi, format->main_width,
            format->main_height, specify) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Failed to set fourth source buffer config!\n"));
        goto error_exit;
    }

    return SGKS_SUCCESS;
error_exit:
    DEBUGMSG(ZONE_ERROR, ("Source buffer size: [%dx%d] [%dx%d] [%dx%d] [%dx%d].\n",
                          format->main_width, format->main_height,
                          format->second_width, format->second_height,
                          format->third_width, format->third_height,
                          format->fourth_width, format->fourth_height));
    return SGKS_ERR_VENC_PARAMERR;
}


static int venc_check_system_buffer_config_limit(int stream, int rotate_flag)
{
    int source, intlc_vi, deintlc_for_intlc_enc;
    u16 src_w, src_h;
    sgks_source_buffer_ex_t *source_buffer = NULL;
    sgks_source_buffer_type_ex_t buffer_type;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    sgks_system_resource_setup_ex_t *resource = &(mpi->system_resource);
    source = pMpiVencHandle->encodeStreams[stream].format.source;
    if(source < SGKS_ENCODE_SOURCE_BUFFER_FIRST)
        //if((source < SGKS_ENCODE_SOURCE_BUFFER_FIRST) || (source > SGKS_ENCODE_SOURCE_BUFFER_LAST));
    {
        DEBUGMSG(ZONE_ERROR, ("Invalid source buffer id [%d] for stream [%d].\n", source, stream));
        return SGKS_ERR_VENC_PARAMERR;
    }

    source_buffer = & mpi->system_source_buff[source];
    buffer_type = source_buffer->type;

    if(buffer_type != SGKS_SOURCE_BUFFER_TYPE_ENCODE)
    {
        DEBUGMSG(ZONE_ERROR, ("Please config buffer [%d] type for encoding!\n", source));
        return SGKS_ERR_VENC_PARAMERR;
    }

    deintlc_for_intlc_enc = source_buffer->format.deintlc_for_intlc_vi;
    intlc_vi = (venc_get_vi_capability()->video_format == SGKS_VIDEO_FORMAT_INTERLACE);

    if(rotate_flag && intlc_vi && (deintlc_for_intlc_enc == DEINTLC_OFF))
    {
        DEBUGMSG(ZONE_ERROR, ("Cannot encode rotated H264 stream [%d] from interlaced buffer [%d]!\n", stream, source));
        return SGKS_ERR_VENC_PARAMERR;
    }

    src_w = source_buffer->format.width;
    src_h = source_buffer->format.height;

    switch(source)
    {
        case SGKS_ENCODE_SOURCE_SECOND_BUFFER:

            if((resource->second_source_buffer_max_width == 0) || (resource->second_source_buffer_max_height == 0))
            {
                DEBUGMSG(ZONE_ERROR, ("Second source buffer is disabled, cannot start encoding from it!\n"));
                return SGKS_ERR_VENC_PARAMERR;
            }

            if((src_w > resource->second_source_buffer_max_width) ||
               (src_h > resource->second_source_buffer_max_height))
            {
                DEBUGMSG(ZONE_ERROR, ("Second source buffer %dx%d is bigger than max size %dx%d.\n",
                                      src_w, src_h,
                                      resource->second_source_buffer_max_width,
                                      resource->second_source_buffer_max_height));
                return SGKS_ERR_VENC_PARAMERR;
            }

            break;
        case SGKS_ENCODE_SOURCE_THIRD_BUFFER:

            if((resource->third_source_buffer_max_width == 0) ||
               (resource->third_source_buffer_max_height == 0))
            {
                DEBUGMSG(ZONE_ERROR, ("Third source buffer is disabled, cannot start encoding from it!\n"));
                return SGKS_ERR_VENC_PARAMERR;
            }

            if((src_w > resource->third_source_buffer_max_width) || (src_h > resource->third_source_buffer_max_height))
            {
                DEBUGMSG(ZONE_ERROR, ("Third source buffer %dx%d is bigger than max size %dx%d.\n",
                                      src_w, src_h,
                                      resource->third_source_buffer_max_width,
                                      resource->third_source_buffer_max_height));
                return SGKS_ERR_VENC_PARAMERR;
            }

            break;
        case SGKS_ENCODE_SOURCE_FOURTH_BUFFER:

            if((resource->fourth_source_buffer_max_width == 0) || (resource->fourth_source_buffer_max_height == 0))
            {
                DEBUGMSG(ZONE_ERROR, ("Fourth source buffer is disabled, cannot start encoding from it!\n"));
                return -1;
            }

            if((src_w > resource->fourth_source_buffer_max_width) || (src_h > resource->fourth_source_buffer_max_height))
            {
                DEBUGMSG(ZONE_ERROR, ("Fourth source buffer %dx%d is bigger than max size %dx%d.\n",
                                      src_w, src_h,
                                      resource->fourth_source_buffer_max_width,
                                      resource->fourth_source_buffer_max_height));
                return SGKS_ERR_VENC_PARAMERR;
            }

            break;
    }

    return SGKS_SUCCESS;
}


static int venc_check_stream_offset(sgks_mpi_venc_format_s *pVencFormat)
{
    sgks_source_buffer_format_ex_t *pSystemSourceBufferFormat = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    pSystemSourceBufferFormat = &mpi->system_source_buff[pVencFormat->source].format;
    if((pVencFormat->encode_width & 0x1) || (pVencFormat->encode_height & 0x1) ||
       (pVencFormat->encode_x & 0x1) || (pVencFormat->encode_y & 0x1))
    {
        DEBUGMSG(ZONE_ERROR, ("Stream size %dx%d and offset %dx%d must be even!\n",
                              pVencFormat->encode_width, pVencFormat->encode_height,
                              pVencFormat->encode_x, pVencFormat->encode_y));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(((pVencFormat->encode_width + pVencFormat->encode_x) > pSystemSourceBufferFormat->width) ||
       ((pVencFormat->encode_height + pVencFormat->encode_y) > pSystemSourceBufferFormat->height))
    {
        DEBUGMSG(ZONE_ERROR, ("Stream size %dx%d with offset %dx%d is out of source buffe %dx%d.\n",
                              pVencFormat->encode_width, pVencFormat->encode_height,
                              pVencFormat->encode_x, pVencFormat->encode_y,
                              pSystemSourceBufferFormat->width, pSystemSourceBufferFormat->height));
        return SGKS_ERR_VENC_PARAMERR;
    }

    return SGKS_SUCCESS;
}


static int venc_check_and_update_encode_resource()
{
    sgks_system_resource_setup_ex_t *pSystemResource = NULL;
    sgks_source_buffer_format_ex_t *pBufFormat = NULL;
    sgks_mpi_venc_stream_params_s *pEncodeStreams = NULL;
    sgks_venc_h264_config_s  *pEncodeH264Config = NULL;
    sgks_mpi_venc_format_s *pEncodeFormat = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    u8 strNum = 0;
    int cnt = 0;

    pSystemResource = &(mpi->system_resource);

    pBufFormat = &(mpi->system_source_buff[VENC_STREAM_FIRST].format);
    if((pSystemResource->main_source_buffer_max_width  != pBufFormat->width) ||
       (pSystemResource->main_source_buffer_max_height != pBufFormat->height))
    {
        /*reset system source limit.*/
        pSystemResource->main_source_buffer_max_width  = pBufFormat->width;
        pSystemResource->main_source_buffer_max_height = pBufFormat->height;
    }

    pBufFormat = &(mpi->system_source_buff[VENC_STREAM_SECOND].format);
    if((pSystemResource->second_source_buffer_max_width  != pBufFormat->width) ||
       (pSystemResource->second_source_buffer_max_height != pBufFormat->height))
    {
        /*reset system source limit.*/
        pSystemResource->second_source_buffer_max_width  = pBufFormat->width;
        pSystemResource->second_source_buffer_max_height = pBufFormat->height;
    }

    pBufFormat = &(mpi->system_source_buff[VENC_STREAM_THIRD].format);
    if((pSystemResource->third_source_buffer_max_width  != pBufFormat->width) ||
       (pSystemResource->third_source_buffer_max_height != pBufFormat->height))
    {
        /*reset system source limit.*/
        pSystemResource->third_source_buffer_max_width  = pBufFormat->width;
        pSystemResource->third_source_buffer_max_height = pBufFormat->height;
    }

    /*check fourth buffer format.*/
    pBufFormat = &(mpi->system_source_buff[VENC_STREAM_FORTH].format);
    if((pSystemResource->fourth_source_buffer_max_width  != pBufFormat->width) ||
       (pSystemResource->fourth_source_buffer_max_height != pBufFormat->height))
    {
        /*reset system source limit.*/
        pSystemResource->fourth_source_buffer_max_width  = pBufFormat->width;
        pSystemResource->fourth_source_buffer_max_height = pBufFormat->height;
    }

    strNum = 0;
    for(cnt = 0; cnt < VENC_STREAM_NUM; cnt++)
    {
        /*check max encode size.*/
        pEncodeStreams =  &(pMpiVencHandle->encodeStreams[cnt]);
        if(pSystemResource->stream_max_encode_size[cnt].width != pEncodeStreams->maxWidth)
        {
            /*reset system source limit.*/
            pSystemResource->stream_max_encode_size[cnt].width = pEncodeStreams->maxWidth;
        }

        if(pSystemResource->stream_max_encode_size[cnt].height != pEncodeStreams->maxHeight)
        {
            /*reset system source limit.*/
            pSystemResource->stream_max_encode_size[cnt].height = pEncodeStreams->maxHeight;
        }

        /*check h264 stream GOP.*/
        pEncodeH264Config = &(pMpiVencHandle->encodeStreams[cnt].config->h264_encode_config);
        if(pSystemResource->stream_max_GOP_N[cnt] != pEncodeH264Config->N)
        {
            /*reset system source limit.*/
            pSystemResource->stream_max_GOP_N[cnt] = pEncodeH264Config->N;
        }

        if(pSystemResource->stream_max_GOP_M[cnt] != pEncodeH264Config->M)
        {
            /*reset system source limit.*/
            pSystemResource->stream_max_GOP_M[cnt] = pEncodeH264Config->M;
        }

        /*get total encode stream number.*/
        pEncodeFormat = &(pMpiVencHandle->encodeStreams[cnt].format);
        if((pEncodeFormat->encode_type == VENC_CONFIG_TYPE_H264) || (pEncodeFormat->encode_type == VENC_CONFIG_TYPE_MJPEG))
        {
            strNum++;
        }
    }

    /*check encode stream number*/
    if(pSystemResource->max_num_encode_streams != strNum)
    {
        /*reset system source limit.*/
        pSystemResource->max_num_encode_streams = strNum;
    }

    return SGKS_SUCCESS;
}

static int venc_check_h264_config(int stream, sgks_venc_h264_config_s *h264_config_ex)
{
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

#define DEBLOCKING_PARAM_MAX        (6)
#define DEBLOCKING_PARAM_MIN        (-6)

    if(h264_config_ex->M > (mpi->system_resource.stream_max_GOP_M[stream]))
    {
        DEBUGMSG(ZONE_ERROR, ("stream [%d]:H264 config M %d is > system resource max GOP M\n", stream, h264_config_ex->M));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(h264_config_ex->N > (mpi->system_resource.stream_max_GOP_N[stream]))
    {
        DEBUGMSG(ZONE_ERROR, ("stream [%d]:H264 config N %d is > system resource max GOP N.\n", stream, h264_config_ex->N));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(h264_config_ex->gop_model > (mpi->system_resource.stream_max_advanced_quality_model[stream]))
    {
        DEBUGMSG(ZONE_ERROR, ("stream [%d]:H264 config gop model %d is > system resource max gop model.\n", stream, h264_config_ex->gop_model));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(h264_config_ex->rotate_clockwise)
    {
        if(h264_config_ex->M > 1)
        {
            DEBUGMSG(ZONE_ERROR, ("stream [%d]:H264 rotate cannot be encoded with B frame!(M = %d)\n", stream, h264_config_ex->M));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }

    if(h264_config_ex->au_type > 3)
    {
        DEBUGMSG(ZONE_ERROR, ("stream [%d]:H264 syntax option -- au type (%d) is out of valid range 0 ~ 3.\n", stream, h264_config_ex->au_type));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(h264_config_ex->slice_alpha_c0_offset_div2 > DEBLOCKING_PARAM_MAX ||
       h264_config_ex->slice_alpha_c0_offset_div2 < DEBLOCKING_PARAM_MIN ||
       h264_config_ex->slice_beta_offset_div2 > DEBLOCKING_PARAM_MAX ||
       h264_config_ex->slice_beta_offset_div2 < DEBLOCKING_PARAM_MIN)
    {
        DEBUGMSG(ZONE_ERROR, ("stream [%d] : H264 deblocking option --slice_alpha(%d)/slice_beta(%d) is out of valid range -6~6.\n",
                              stream, h264_config_ex->slice_alpha_c0_offset_div2, h264_config_ex->slice_beta_offset_div2));
        return SGKS_ERR_VENC_PARAMERR;
    }

    return SGKS_SUCCESS;
}

static int venc_check_source_buffer_property(u32 source_buffer_id, u32 buffer_width, u32 buffer_height,
        u32 input_width, u32 input_height)
{
    sgks_mpi_manager_s *mpi = NULL;
    sgks_source_buffer_type_ex_t type;
    sgks_source_buffer_property_ex_t *pProperty =NULL;

    mpi = mpi_get_managerHanle();
    type = mpi->system_source_buff[source_buffer_id].type;
    pProperty = &(mpi->system_source_buff[source_buffer_id].property);

    if((buffer_width > pProperty->max_width) || (buffer_height > pProperty->max_height))
    {
        DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] size %dx%d too big, can only be up to %dx%d.\n",
                              source_buffer_id, buffer_width, buffer_height,
                              pProperty->max_width, pProperty->max_height));
        goto error_exit;
    }

    if(SGKS_SOURCE_BUFFER_TYPE_ENCODE == type)
    {
        if(((pProperty->max_zoom_out_factor * buffer_width) < input_width) ||
           ((pProperty->max_zoom_out_factor * buffer_height) < input_height))
        {
            DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] downscaled from %dx%d to %dx%d"
                                  ", out of the max zoom out factor [%d].\n", source_buffer_id,
                                  input_width, input_height, buffer_width, buffer_height,
                                  pProperty->max_zoom_out_factor));
            goto error_exit;
        }

        if(((pProperty->max_zoom_in_factor * input_width) < buffer_width) ||
           ((pProperty->max_zoom_in_factor * input_height) < buffer_height))
        {
            DEBUGMSG(ZONE_ERROR, ("Source buffer [%d] upscaled from %dx%d to %dx%d"
                                  ", out of the max zoom in factor [%d].\n", source_buffer_id,
                                  input_width, input_height, buffer_width, buffer_height,
                                  pProperty->max_zoom_in_factor));
            goto error_exit;
        }
    }

    return SGKS_SUCCESS;
error_exit:
    DEBUGMSG(ZONE_ERROR, ("Please refer to documents to check the supported zoom factor.\n"));
    return SGKS_ERR_VENC_PARAMERR;
}

static int venc_check_digital_zoom_format(sgks_venc_digital_zoom_s *pDigitalZoom)
{
#define    MAX_ZOOM_FACTOR_Y        (4 << 16)
#define    MAX_OFFSET_Y_MARGIN        (4)
    int cap_width, cap_height;
    u32 zoom_factor_x, zoom_factor_y;
    int max_offset_x, max_offset_y, curr_offset_x, curr_offset_y;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    sgks_source_buffer_format_ex_t *buffer_format = &(mpi->system_source_buff[0].format);
    sgks_vi_src_capability_s *current_vi_info = venc_get_vi_capability();
    curr_offset_x = (int)pDigitalZoom->center_offset_x / 65536;
    curr_offset_y = (int)pDigitalZoom->center_offset_y / 65536;
    zoom_factor_x = pDigitalZoom->zoom_factor_x;
    zoom_factor_y = pDigitalZoom->zoom_factor_y;

    if((zoom_factor_x == 0) || (zoom_factor_y == 0))
    {
        DEBUGMSG(ZONE_ERROR, ("Zoom factor x [%d]/y [%d] cannot be 0!\n", zoom_factor_x, zoom_factor_y));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // auto correct alignment
    cap_width = (int)(buffer_format->width << 16) / pDigitalZoom->zoom_factor_x;
    cap_height = (int)(buffer_format->height << 16) / pDigitalZoom->zoom_factor_y;
    cap_width = ROUND_UP(cap_width, 4);
    cap_height = ROUND_UP(cap_height, 4);

    if((cap_width > current_vi_info->cap_width) || (cap_height > current_vi_info->cap_height))
    {
        DEBUGMSG(ZONE_ERROR, ("main capture window %dx%d, cannot be larger than VI %dx%d.\n",
                              cap_width, cap_height, current_vi_info->cap_width, current_vi_info->cap_height));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if((cap_width == 0) || (cap_height == 0))
    {
        DEBUGMSG(ZONE_ERROR, ("Too large zoom factor cause cpature window to be 0x0!\n"));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check main buffer property with VI window
    if(venc_check_source_buffer_property(SGKS_ENCODE_SOURCE_MAIN_BUFFER,
                                         buffer_format->width, buffer_format->height, cap_width, cap_height) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    zoom_factor_x = (int)(buffer_format->width << 16) / cap_width;
    zoom_factor_y = (int)(buffer_format->height << 16) / cap_height;
    // auto correct for zoom offset
    max_offset_x = current_vi_info->cap_width / 2 - cap_width / 2;
    max_offset_y = current_vi_info->cap_height / 2 - cap_height / 2;

    if(zoom_factor_y >= MAX_ZOOM_FACTOR_Y)
    {
        max_offset_y -= MAX_OFFSET_Y_MARGIN;
    }
    /*
        DEBUGMSG(ZONE_INFO, ("vi %dx%d, main capture window %dx%d, center offset %dx%d.\n",
                             current_vi_info->cap_width, current_vi_info->cap_height,
                             cap_width, cap_height, curr_offset_x, curr_offset_y));
    */
    if(curr_offset_x < -max_offset_x || curr_offset_x > max_offset_x ||
       curr_offset_y < -max_offset_y || curr_offset_y > max_offset_y)
    {
        DEBUGMSG(ZONE_ERROR, ("Current offset %dx%d is out of valid range X (%dx~%d) Y (%d~%d)!\n",
                              curr_offset_x, curr_offset_y, -max_offset_x, max_offset_x,
                              -max_offset_y, max_offset_y));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // update main capture window and zoom factor
    pDigitalZoom->zoom_factor_x = zoom_factor_x;
    pDigitalZoom->zoom_factor_y = zoom_factor_y;
    buffer_format->input_width = cap_width;
    buffer_format->input_height = cap_height;
    buffer_format->input_offset_x = max_offset_x + curr_offset_x;
    buffer_format->input_offset_y = max_offset_y + curr_offset_y;
    return SGKS_SUCCESS;
}


static int venc_check_2nd_digital_zoom_format(sgks_venc_digital_zoom2_s *digital_zoom)
{
    u32 buffer_id = digital_zoom->source;
    int ret = SGKS_SUCCESS;
    sgks_source_buffer_format_ex_t source, *buffer_format = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    buffer_id = digital_zoom->source;

    // error if source is not sub source buffer id
    if((buffer_id < SGKS_ENCODE_SUB_SOURCE_BUFFER_FIRST) || (buffer_id >= SGKS_ENCODE_SUB_SOURCE_BUFFER_LAST))
    {
        DEBUGMSG(ZONE_ERROR, ("Invalid source buffer [%d], not supported!\n", buffer_id));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // error if second is BOB, while main is not BOB
    buffer_format = &(mpi->system_source_buff[buffer_id].format);

    if(buffer_id == SGKS_ENCODE_SOURCE_SECOND_BUFFER)
    {
        if((mpi->system_source_buff[0].format.deintlc_for_intlc_vi != DEINTLC_BOB_MODE) &&
           (buffer_format->deintlc_for_intlc_vi == DEINTLC_BOB_MODE))
        {
            DEBUGMSG(ZONE_ERROR, ("Digital zoom type II can't run when second buffer is BOB mode,"
                                  " while main is not BOB mode.\n"));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }

    memset(&source, 0, sizeof(source));
    source.width = buffer_format->width;
    source.height = buffer_format->height;
    source.deintlc_for_intlc_vi = buffer_format->deintlc_for_intlc_vi;
    source.input_width = digital_zoom->input_width;
    source.input_height = digital_zoom->input_height;
    source.input_offset_x = digital_zoom->input_offset_x;
    source.input_offset_y = digital_zoom->input_offset_y;

    ret = venc_check_system_sub_source_buffer_config(buffer_id, &source,
            mpi->system_source_buff[0].format.deintlc_for_intlc_vi,
            mpi->system_source_buff[0].format.width,
            mpi->system_source_buff[0].format.height, NULL);

    if(ret != SGKS_SUCCESS)
    {
        return ret;
    }


    return ret;
}

static int venc_check_start_encode_state(u32 stream)
{
    int i, encoding_counter;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    encoding_counter = 0;

    for(i = 0; i < MULTI_STREAM_MAX_NUM; ++i)
    {
        if(stream & (1 << i))
        {
            if(pMpiVencHandle->encodeStreams[i].state != VENC_STREAM_STATE_READY_FOR_ENCODING)
            {
                DEBUGMSG(ZONE_ERROR, ("stream %d is NOT ready for encoding.\n", i));
                return SGKS_ERR_VENC_STATEERROR;
            }

            if(pMpiVencHandle->encodeStreams[i].format.encode_type == SGKS_ENCODE_NONE)
            {
                DEBUGMSG(ZONE_ERROR, ("encode type is NOT set for stream %d.\n", i));
                return SGKS_ERR_VENC_PARAMERR;
            }
            ++encoding_counter;
        }
    }

    if(encoding_counter > (mpi->system_resource.max_num_encode_streams))
    {
        DEBUGMSG(ZONE_ERROR, ("Total encode stream num [%d] is over than max num [%d].\n",
                              encoding_counter, (mpi->system_resource.max_num_encode_streams)));
        return SGKS_ERR_VENC_PARAMERR;
    }

    return SGKS_SUCCESS;
}


// used for start encode of 0x6003 command and overlay of 0x6007 command
int venc_check_encode_format_limit(u32 stream_id)
{
    int i;
    u32 total_resoution = 0;
    u16 is_h264_flag, rotate_flag, enc_w, enc_h;
    sgks_venc_h264_config_s *config = NULL;
    sgks_mpi_venc_format_s *format = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    sgks_system_resource_setup_ex_t *resource = &(mpi->system_resource);

    for(i = 0; i < MULTI_STREAM_MAX_NUM; ++i)
    {
        if(stream_id & (1 << i))
        {

            format = &pMpiVencHandle->encodeStreams[i].format;
            is_h264_flag = venc_is_h264_stream(i);
            rotate_flag = is_h264_flag ? pMpiVencHandle->encodeStreams[i].config->h264_encode_config.rotate_clockwise :
                          pMpiVencHandle->encodeStreams[i].config->jpeg_encode_config.rotate_clockwise;

            if(rotate_flag)
            {
                enc_w = format->encode_height;
                enc_h = format->encode_width;
            }
            else
            {
                enc_w = format->encode_width;
                enc_h = format->encode_height;
            }

            /*
             * First check source buffer configuration limit to make sure
             * the source buffer is available and correct.
             */
            if(venc_check_system_buffer_config_limit(i, rotate_flag) < 0)
            {
                DEBUGMSG(ZONE_ERROR, ("Cannot start encode, invalid buffer configuration!\n"));
                return SGKS_ERR_VENC_PARAMERR;
            }

            /*
             * Then check stream configuration, including offset, min and max
             * encode size, limitation for stream rotation and H.264.
             */
            if((format->encode_width & 0x1) || (format->encode_height & 0x1) ||
               (format->encode_x & 0x1) || (format->encode_y & 0x1))
            {
                DEBUGMSG(ZONE_ERROR, ("Stream size %dx%d and offset %dx%d must be even!\n",
                                      format->encode_width, format->encode_height,
                                      format->encode_x, format->encode_y));
                return SGKS_ERR_VENC_PARAMERR;
            }

            if(((format->encode_width + format->encode_x) > mpi->system_source_buff[format->source].format.width) ||
               ((format->encode_height + format->encode_y) > mpi->system_source_buff[format->source].format.height))
            {
                DEBUGMSG(ZONE_ERROR, ("Stream size %dx%d with offset %dx%d is out of source buffe\n",
                                      format->encode_width, format->encode_height,
                                      format->encode_x, format->encode_y));
                return SGKS_ERR_VENC_PARAMERR;
            }


            // check the minimum encode size
            if((enc_w < g_encode_limit.width_min) || (enc_h < g_encode_limit.height_min))
            {
                DEBUGMSG(ZONE_ERROR, ("Encoding size %dx%d (rotate: %d) cannot be smaller than %dx%d!\n",
                                      enc_w, enc_h, rotate_flag,
                                      g_encode_limit.width_min, g_encode_limit.height_min));
                return SGKS_ERR_VENC_PARAMERR;
            }

            if(is_h264_flag)
            {
                // check H264 rotate limit
                if(rotate_flag && (enc_w < g_encode_limit.h264_rotate_width_min))
                {
                    DEBUGMSG(ZONE_ERROR, ("H264 encoding width %d (rotate: %d) cannot be smaller than %d!\n",
                                          enc_w, rotate_flag, g_encode_limit.h264_rotate_width_min));
                    return SGKS_ERR_VENC_PARAMERR;
                }

                // check max GOP M in system resource limit
                config = &(pMpiVencHandle->encodeStreams[i].config->h264_encode_config);
                if(config->M > resource->stream_max_GOP_M[i])
                {
                    DEBUGMSG(ZONE_ERROR, ("Stream [%d] GOP M %d is bigger than max GOP M %d."
                                          " Please increase the stream max M by SGKS_MEDIA_IOC_SET_SYSTEM_RESOURCE_LIMIT_EX\n",
                                          i, config->M, resource->stream_max_GOP_M[i]));
                    return SGKS_ERR_VENC_PARAMERR;
                }
            }

            // check max encode size with system resource limit
            if((enc_w > resource->stream_max_encode_size[i].width) ||
               (enc_h > resource->stream_max_encode_size[i].height))
            {
                DEBUGMSG(ZONE_ERROR, ("Stream [%d] encoding size %dx%d is bigger than max size %dx%d."
                                      " Please increase the stream max size by SGKS_MEDIA_IOC_SET_SYSTEM_RESOURCE_LIMIT_EX\n",
                                      i, enc_w, enc_h,
                                      resource->stream_max_encode_size[i].width,
                                      resource->stream_max_encode_size[i].height));
                return SGKS_ERR_VENC_PARAMERR;
            }

            total_resoution += (format->encode_width) * (format->encode_height);
        }
    }


    if(total_resoution > SGKS_TOTAL_RESOLUTION_LIMIT)           // 1080p+1080p+480p+cif
    {
        DEBUGMSG(ZONE_ERROR, ("total resoution %d exceed maximum of %d\n", total_resoution, SGKS_TOTAL_RESOLUTION_LIMIT));
        return SGKS_ERR_VENC_PARAMERR;
    }

    return SGKS_SUCCESS;
}

static int venc_check_before_start_encode(u32 stream_id)
{
    int i;
    u32 sys_status = 0;
    sgks_vi_src_capability_s *current_vi_info = venc_get_vi_capability();
    sgks_mpi_dsp_status_s   curr_dsp_state;

    if(SGKS_SUCCESS != sgks_mpi_sys_GetDspStats(&curr_dsp_state))
    {
        DEBUGMSG(ZONE_ERROR, ("Get DSP STATE FAIL\n"));
        return SGKS_ERR_VENC_DEVICEERR;
    }

    if((curr_dsp_state.state != SGKS_ENC_IDLE_STATE ) && (curr_dsp_state.state != SGKS_ENC_BUSY_STATE))
    {
        DEBUGMSG(ZONE_ERROR, ("Can't start encode, not in preview state, please enable preview first\n"));
        return SGKS_ERR_VENC_STATEERROR;
    }

    // check total encode performance limit
    if(venc_check_encode_resource_limit(stream_id, current_vi_info->frame_rate) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("cannot start encode, system resource is not enough.\n"));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check total encode size limit
    if(venc_check_encode_format_limit(stream_id) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("cannot start encode, encode format configuration is invalid.\n"));
        return SGKS_ERR_VENC_PARAMERR;
    }

    return SGKS_SUCCESS;
}

static int venc_check_stop_encode_state(int stream)
{
    int i, encoding_counter;
    u32 sys_status = 0;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    encoding_counter = 0;
    for(i = 0; i < MULTI_STREAM_MAX_NUM; ++i)
    {
        if(stream & (1 << i))
        {
            if(pMpiVencHandle->encodeStreams[i].state != VENC_STREAM_STATE_ENCODING)
            {
                DEBUGMSG(ZONE_INFO, ("Cannot stop stream %d, not in encoding.\n", i));
                continue;
            }
            ++encoding_counter;
        }
    }
    if(encoding_counter > (mpi->system_resource.max_num_encode_streams))
    {
        DEBUGMSG(ZONE_ERROR, ("Total encode stream num [%d] is over than max num [%d].\n",
                              encoding_counter, mpi->system_resource.max_num_encode_streams));
        return SGKS_ERR_VENC_STATEERROR;
    }
    return SGKS_SUCCESS;
}


static inline int venc_update_system_resource_limit(sgks_system_resource_setup_ex_t *resource)
{
    sgks_mpi_manager_s *mpi =NULL;
    sgks_source_buffer_format_ex_t *buffer_format = NULL;
    sgks_system_resource_setup_ex_t       *pSystemResourceBuffer = NULL;

    mpi = mpi_get_managerHanle();
    if(mpi == NULL)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: mpi is null %s\n", __FUNCTION__));
        return SGKS_ERR_SYS_INITFAIL;
    }
    pSystemResourceBuffer = &mpi->system_resource;
    memcpy(pSystemResourceBuffer, resource, sizeof(sgks_system_resource_setup_ex_t));

    //G_system_resource_setup = *resource;

    buffer_format =  &mpi->system_source_buff[SGKS_ENCODE_SOURCE_SECOND_BUFFER].format;
    if(buffer_format->width > pSystemResourceBuffer->second_source_buffer_max_width)
    {
        buffer_format->width = pSystemResourceBuffer->second_source_buffer_max_width;
    }
    if(buffer_format->height > pSystemResourceBuffer->second_source_buffer_max_height)
    {
        buffer_format->height = pSystemResourceBuffer->second_source_buffer_max_height;
    }

    buffer_format =  &mpi->system_source_buff[SGKS_ENCODE_SOURCE_THIRD_BUFFER].format;
    if(buffer_format->width > pSystemResourceBuffer->third_source_buffer_max_width)
    {
        buffer_format->width = pSystemResourceBuffer->third_source_buffer_max_width;
    }
    if(buffer_format->height > pSystemResourceBuffer->third_source_buffer_max_height)
    {
        buffer_format->height = pSystemResourceBuffer->third_source_buffer_max_height;
    }

    buffer_format =  &mpi->system_source_buff[SGKS_ENCODE_SOURCE_FOURTH_BUFFER].format;
    if(buffer_format->width > pSystemResourceBuffer->fourth_source_buffer_max_width)
    {
        buffer_format->width = pSystemResourceBuffer->fourth_source_buffer_max_width;
    }
    if(buffer_format->height > pSystemResourceBuffer->fourth_source_buffer_max_height)
    {
        buffer_format->height = pSystemResourceBuffer->fourth_source_buffer_max_height;
    }

    pSystemResourceBuffer->max_num_cap_sources = venc_calc_max_num_cap_sources();
    return SGKS_SUCCESS;
}

static int venc_update_system_source_buffer_format_all( sgks_source_buffer_format_all_s *format)
{
    sgks_source_buffer_format_ex_t *buf_format = NULL;
    sgks_source_buffer_ex_t  *pSourceBuffer = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    buf_format = &mpi->system_source_buff[SGKS_ENCODE_SOURCE_MAIN_BUFFER].format;
    buf_format->width = format->main_width;
    buf_format->height = format->main_height;
    buf_format->deintlc_for_intlc_vi = format->main_deintlc_for_intlc_vi;
    buf_format->intlc_scan = format->intlc_scan;

    buf_format = &mpi->system_source_buff[SGKS_ENCODE_SOURCE_SECOND_BUFFER].format;
    buf_format->width = format->second_width;
    buf_format->height = format->second_height;
    buf_format->input_width = format->second_input_width;
    buf_format->input_height = format->second_input_height;
    buf_format->input_offset_x = (format->main_width - format->second_input_width) / 2;
    buf_format->input_offset_y = (format->main_height - format->second_input_height) / 2;
    buf_format->deintlc_for_intlc_vi = format->second_deintlc_for_intlc_vi;
    buf_format->intlc_scan = format->intlc_scan;

    buf_format = &mpi->system_source_buff[SGKS_ENCODE_SOURCE_THIRD_BUFFER].format;
    buf_format->width = format->third_width;
    buf_format->height = format->third_height;
    buf_format->input_width = format->third_input_width;
    buf_format->input_height = format->third_input_height;
    buf_format->input_offset_x = (format->main_width - format->third_input_width) / 2;
    buf_format->input_offset_y = (format->main_height - format->third_input_height) / 2;
    buf_format->deintlc_for_intlc_vi = format->third_deintlc_for_intlc_vi;
    buf_format->intlc_scan = format->intlc_scan;

    buf_format = &mpi->system_source_buff[SGKS_ENCODE_SOURCE_FOURTH_BUFFER].format;
    buf_format->width = format->fourth_width;
    buf_format->height = format->fourth_height;
    buf_format->input_width = format->fourth_input_width;
    buf_format->input_height = format->fourth_input_height;
    buf_format->input_offset_x = (format->main_width - format->fourth_input_width) / 2;
    buf_format->input_offset_y = (format->main_height - format->fourth_input_height) / 2;
    buf_format->deintlc_for_intlc_vi = format->fourth_deintlc_for_intlc_vi;
    buf_format->intlc_scan = format->intlc_scan;

    return SGKS_SUCCESS;
}

static inline int venc_update_preview_buffer_format(sgks_preview_buffer_format_all_s *format)
{
    sgks_vio_src_video_info_s *vo_info = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    vo_info = &mpi->mpi_vo_dev[0].vo_user_param.video_info;

    if(vo_info->rotate)
    {
        format->second_preview_width = vo_info->height;
        format->second_preview_height = vo_info->width;
    }
    else
    {
        format->second_preview_width = vo_info->width;
        format->second_preview_height = vo_info->height;
    }

    vo_info = &mpi->mpi_vo_dev[1].vo_user_param.video_info;
    if(vo_info->rotate)
    {
        format->main_preview_width = vo_info->height;
        format->main_preview_height = vo_info->width;
    }
    else
    {
        format->main_preview_width = vo_info->width;
        format->main_preview_height = vo_info->height;
    }

    return SGKS_SUCCESS;
}

static int venc_set_system_source_buffer_format_all(sgks_source_buffer_format_all_s *pSystemBufferFormat)
{
    sgks_source_buffer_format_all_s  buffer_format_all;
    int specify[MAX_SOURCE_BUFFER_NUM];
    int i = 0;
    u32 sys_status = 0;

    sgks_mpi_sys_GetStats(&sys_status);

    memcpy(&buffer_format_all, pSystemBufferFormat, sizeof(sgks_source_buffer_format_all_s));
    if(venc_check_system_source_buffer_config_all(&buffer_format_all, specify) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }
    venc_update_system_source_buffer_format_all(&buffer_format_all);
    if(sys_status == STATE_PREVIEW || sys_status == STATE_ENCODING)
    {
        for(i = SGKS_ENCODE_SUB_SOURCE_BUFFER_FIRST;
            i < SGKS_ENCODE_SUB_SOURCE_BUFFER_LAST; ++i)
        {
            if(specify[i])
            {
                venc_cmd_capture_preview_buffer_setup(i);
            }
        }
    }

    return SGKS_SUCCESS;
}

static int venc_set_system_source_buffer_type_all(sgks_source_buffer_type_all_s *pSourceBufferType)
{
    sgks_source_buffer_type_all_s source_buffer_type_all;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    /*
        u32 sys_status = 0;
        sgks_mpi_venc_get_state(&sys_status);
        if(sys_status != STATE_IDLE)
        {
            DEBUGMSG(ZONE_ERROR, ("set_source_buffer_type_all must be called in MEDIA IDLE state!\n"));
            return SGKS_ERR_VENC_STATEERROR;
        }
    */
    memcpy(&source_buffer_type_all, pSourceBufferType, sizeof(sgks_source_buffer_type_all_s));

    // update source buffer type and system resource
    mpi->system_source_buff[0].type = source_buffer_type_all.main_buffer_type;
    mpi->system_source_buff[1].type = source_buffer_type_all.second_buffer_type;
    mpi->system_source_buff[2].type = source_buffer_type_all.third_buffer_type;
    mpi->system_source_buff[3].type = source_buffer_type_all.fourth_buffer_type;
    mpi->system_resource.max_num_cap_sources = venc_calc_max_num_cap_sources();

    return SGKS_SUCCESS;
}

static int venc_set_system_resource_limit(sgks_system_resource_setup_ex_t *pSystemResource)
{
    sgks_system_resource_setup_ex_t system_resource;
    u32 sys_status = 0;
    sgks_mpi_sys_GetStats(&sys_status);

    if(sys_status != STATE_IDLE)
    {
        DEBUGMSG(ZONE_ERROR, ("set_system_resource_limit must be called in MEDIA IDLE state!\n"));
        return SGKS_ERR_VENC_PARAMERR;
    }

    memcpy(&system_resource, pSystemResource, sizeof(system_resource));

    if(venc_check_system_resource_limit(&system_resource) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    venc_update_system_resource_limit(&system_resource);
    return SGKS_SUCCESS;
}



static int venc_set_encode_format( sgks_mpi_venc_format_s *pVencFormatParam)
{
    sgks_mpi_venc_format_s *pFormat = NULL;
    int stream_id = 0, ret = SGKS_SUCCESS;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    stream_id = pVencFormatParam->id;
    //if unchanged, then do nothing
    pFormat = &pMpiVencHandle->encodeStreams[stream_id].format;

    if((pFormat->encode_type != pVencFormatParam ->encode_type)  ||
       (pFormat->encode_height != pVencFormatParam->encode_height) ||
       (pFormat->encode_width != pVencFormatParam->encode_width) ||
       (pFormat->source != pVencFormatParam->source) ||
       (pFormat->encode_x != pVencFormatParam->encode_x) ||
       (pFormat->encode_y != pVencFormatParam->encode_y))
    {
        return SGKS_SUCCESS;
    }

    if(venc_is_stream_in_encoding(stream_id))
    {
        //can only change offset x and y once in encoding
        if((pFormat->encode_type == pVencFormatParam ->encode_type) &&
           (pFormat->encode_height == pVencFormatParam->encode_height) &&
           (pFormat->encode_width == pVencFormatParam->encode_width) &&
           (pFormat->source == pVencFormatParam->source))
        {
            if(venc_check_stream_offset(pVencFormatParam) < 0)
            {
                return SGKS_ERR_VENC_PARAMERR;
            }
            memcpy(pFormat, pVencFormatParam, sizeof(sgks_mpi_venc_format_s));
            ret = venc_cmd_encode_size_setup(stream_id);
            if(ret != SGKS_SUCCESS)
            {
                DEBUGMSG(ZONE_ERROR, ("%s:send encode size setup cmd fail\n", __FUNCTION__));
            }
        }
        else
        {
            DEBUGMSG(ZONE_ERROR, ("CANNOT modify stream %d format except offset when in encoding.\n", stream_id));
            return SGKS_ERR_VENC_PARAMERR;
        }
    }
    else
    {
        memcpy(pFormat, pVencFormatParam, sizeof(sgks_mpi_venc_format_s));
    }

    return ret;
}

static int venc_set_h264_config(sgks_venc_h264_config_s  *pVencH264Config)
{
    sgks_venc_h264_config_s config;
    int stream_id = 0;
    u32 flags = 0;

    memcpy(&config, pVencH264Config, sizeof(config));
    stream_id = config.id;
    if(venc_calc_quality_model(&config) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Error: calculate quality return error %s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(venc_check_h264_config(stream_id, &config) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("h264 config for stream %d is invalid.\n", stream_id));
        return SGKS_ERR_VENC_PARAMERR;
    }

    if(pMpiVencHandle->encodeStreams[stream_id].config->h264_encode_config.slice_alpha_c0_offset_div2 !=
       config.slice_alpha_c0_offset_div2 ||
       pMpiVencHandle->encodeStreams[stream_id].config->h264_encode_config.slice_beta_offset_div2 !=
       config.slice_beta_offset_div2)
    {
        flags |= VENC_REALTIME_PARAM_BIAS_VALUE_BIT;
    }

    memcpy(&pMpiVencHandle->encodeStreams[stream_id].config->h264_encode_config, &config, sizeof(config));
    if((flags != 0) && venc_is_stream_in_h264_encoding(stream_id))
    {
        if(venc_cmd_update_encode_params(stream_id, flags) < 0)
        {
            DEBUGMSG(ZONE_ERROR, ("Update encode param return error %s\n", __FUNCTION__));
            return SGKS_ERR_VENC_SENDCMDFAIL;
        }
    }

    return SGKS_SUCCESS;
}

static int venc_set_digital_zoom(sgks_venc_digital_zoom_s  *pDigitalZoom)
{
    sgks_venc_digital_zoom_s digital_zoom;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    sgks_mpi_dsp_status_s   curr_dsp_state;

    if(SGKS_SUCCESS != sgks_mpi_sys_GetDspStats(&curr_dsp_state))
    {
        DEBUGMSG(ZONE_ERROR, ("Get DSP STATE FAIL\n"));
        return SGKS_ERR_VENC_DEVICEERR;
    }

    if((curr_dsp_state.state != SGKS_ENC_IDLE_STATE ) && (curr_dsp_state.state != SGKS_ENC_BUSY_STATE))
    {
        DEBUGMSG(ZONE_ERROR, ("Cannot set digital zoom in non preview/encoding.%s\n", __FUNCTION__));
        return SGKS_ERR_VENC_STATEERROR;
    }
    memcpy(&digital_zoom, pDigitalZoom, sizeof(digital_zoom));

    // check MCTF function
    if(mpi->system_resource.MCTF_possible !=1)
    {
        DEBUGMSG(ZONE_ERROR, ("MCTF is disabled, cannot set digital zoom!%s\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    // check zoom factor and offset
    if(venc_check_digital_zoom_format(&digital_zoom) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    venc_cmd_warp_control(&digital_zoom);
    memcpy(&g_digital_zoom, &digital_zoom, sizeof(sgks_venc_digital_zoom_s));

    return SGKS_SUCCESS;
}

static int venc_set_2nd_digital_zoom_ex(sgks_venc_digital_zoom2_s  *pDigitalZoom2)
{
    int buffer_id = 0;
    u32 sys_status = 0;
    sgks_venc_digital_zoom2_s digital_zoom;
    sgks_source_buffer_format_ex_t *buffer_format = NULL;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    memcpy(&digital_zoom, pDigitalZoom2, sizeof(digital_zoom));

    // check media state
    sgks_mpi_sys_GetStats(&sys_status);

    // check media state
    if((sys_status != STATE_PREVIEW) && (sys_status != STATE_ENCODING))
    {
        DEBUGMSG(ZONE_ERROR, ("Cannot set digital zoom in non preview/encoding.%s\n", __FUNCTION__));
        return SGKS_ERR_VENC_STATEERROR;
    }

    // check zoom out window size and offset
    if(venc_check_2nd_digital_zoom_format(&digital_zoom) < 0)
    {
        return SGKS_ERR_VENC_PARAMERR;
    }

    buffer_id = digital_zoom.source;

    buffer_format = &mpi->system_source_buff[buffer_id].format;
    buffer_format->input_width = digital_zoom.input_width;
    buffer_format->input_height = digital_zoom.input_height;
    buffer_format->input_offset_x = digital_zoom.input_offset_x;
    buffer_format->input_offset_y = digital_zoom.input_offset_y;
    venc_cmd_capture_preview_buffer_setup(buffer_id);
    return SGKS_SUCCESS;
}



static int venc_get_h264_config(sgks_venc_h264_config_s *pH264Config)
{
    sgks_venc_h264_config_s config;
    int stream_id = 0;

    stream_id = pH264Config->id;
    memcpy(&config, &(pMpiVencHandle->encodeStreams[stream_id].config->h264_encode_config), sizeof(sgks_venc_h264_config_s));
    // get pic info playback
    venc_get_pic_info_in_h264(stream_id, &config);
    memcpy(pH264Config, &config, sizeof(config));

    return SGKS_SUCCESS;
}

static inline int venc_get_gcd(int a, int b)
{
    if((a == 0) || (b == 0))
    {
        DEBUGMSG(ZONE_ERROR, ("wrong input for gcd \n"));
        return 1;
    }

    while((a != 0) && (b != 0))
    {
        if(a > b)
        {
            a = a % b;
        }
        else
        {
            b = b % a;
        }
    }

    return (a == 0) ? b : a;
}

static inline int venc_get_colour_primaries(int stream, u32 *color_primaries,
        u32 *transfer_characteristics, u32 *matrix_coefficients)
{
    int width, height;

    width = pMpiVencHandle->encodeStreams[stream].format.encode_width;
    height = pMpiVencHandle->encodeStreams[stream].format.encode_height;

    if(((width == 720) && (height == 480)) ||
       ((width == 704) && (height == 480))  ||
       ((width == 352) && (height == 240)))
    {
        //NTSC
        *color_primaries = 6;
        *transfer_characteristics = 6;
        *matrix_coefficients = 6;
    }
    else if(((width == 720) && (height == 576)) ||
            ((width == 704) && (height == 576)) ||
            ((width == 352) && (height == 288)))
    {
        //PAL
        *color_primaries = 5;
        *transfer_characteristics = 5;
        *matrix_coefficients = 5;
    }
    else
    {
        //default
        *color_primaries = 1;
        *transfer_characteristics = 1;
        *matrix_coefficients = 1;
    }

    return SGKS_SUCCESS;
}

static inline int venc_get_aspect_ratio(int buffer_id, u8 *aspect_ratio_idc, u16 *sar_width, u16 *sar_height)
{
    sgks_source_buffer_format_ex_t *buffer = NULL;
    int gcd, num, den;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    buffer = &(mpi->system_source_buff[buffer_id].format);
    num = buffer->input_width * buffer->height;
    den = buffer->input_height * buffer->width;
    gcd = venc_get_gcd(num, den);
    num = num / gcd * (*sar_width);
    den = den / gcd * (*sar_height);

    if(num == den)
    {
        //square pixel, 1:1
        *aspect_ratio_idc = VENC_ASPECT_RATIO_1_1_SQUARE_PIXEL;
        *sar_width = 1;
        *sar_height = 1;
    }
    else
    {
        *aspect_ratio_idc = VENC_ASPECT_RATIO_CUSTOM;
        gcd = venc_get_gcd(num, den);
        *sar_width = num / gcd;
        *sar_height = den / gcd;
    }

    return SGKS_SUCCESS;
}


static int venc_encode_init()
{

    return SGKS_SUCCESS;
}

static int venc_encode_start(u32 stream_id)
{
    int ret = SGKS_SUCCESS;
    int i = 0;
    u32 sys_status = 0;
    sgks_mpi_dsp_status_s   curr_dsp_state;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    struct timeval tv1, tv2;

    ret = venc_check_before_start_encode(stream_id);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Check return error.%s", __FUNCTION__));
        return ret;
    }

    ret = sgks_mpi_sys_GetDspStats(&curr_dsp_state);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Get DSP STATE FAIL\n"));
        ret = SGKS_ERR_VENC_DEVICEERR;
    }

    if(curr_dsp_state.op_mode == SGKS_DSP_ENCODE_MODE)
    {
        if(curr_dsp_state.state == SGKS_ENC_IDLE_STATE)
        {
            venc_encode_init();
        }
    }

    gettimeofday(&tv1, NULL);
    sgks_mpi_cmd_SetMode(mpi, SGKS_MDI_CMD_MODE_BLOCK_LOADING);
    //usleep(20*1000);

    //encode setup for all streams
    for(i = 0; i < MULTI_STREAM_MAX_NUM; i++)
    {
        if(stream_id & (1 << i))
        {
            {
                int *msg_buf = NULL;
                SGKS_MDI_DRV_BUFF(msg_buf);
                *msg_buf = i;
                SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_CREATE_SESSION_ID, 0, sizeof(u32), SGKS_ERR_SYS_DRIVERIOCTLERR);
            }
            if(venc_is_h264_stream(i))
            {
                ret = venc_cmd_encode_size_setup(i);
                if(ret != SGKS_SUCCESS)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s:send command encode_size_setup fail\n", __FUNCTION__));
                    return ret;
                }

                ret = venc_cmd_h264_encode_setup(i);
                if(ret != SGKS_SUCCESS)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s:send command h264_encode_setup fail\n", __FUNCTION__));
                    return ret;
                }

            }
            else if(venc_is_mjpeg_stream(i))
            {
                ret = venc_cmd_encode_size_setup(i);
                if(ret != SGKS_SUCCESS)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s:send command encode_size_setup fail\n", __FUNCTION__));
                    return ret;
                }
                ret = venc_cmd_jpeg_encode_setup(i, 1);
                if(ret != SGKS_SUCCESS)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s:send command jpeg_encode_setup fail\n", __FUNCTION__));
                    return ret;
                }
            }
        }
    }

    for(i = 0; i < MULTI_STREAM_MAX_NUM; i++)
    {
        if(stream_id & (1 << i))
        {
            if(venc_is_h264_stream(i))
            {
                ret = venc_cmd_h264_encode_start(i);
                if(ret != SGKS_SUCCESS)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s:send command h264_encode_start fail\n", __FUNCTION__));
                    return ret;
                }
            }
            else if(venc_is_mjpeg_stream(i))
            {
                ret = venc_cmd_jpeg_encode_start(i);
                if(ret != SGKS_SUCCESS)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s:send command jpeg_encode_start fail\n", __FUNCTION__));
                    return ret;
                }
            }
        }
    }

    sgks_mpi_cmd_SetMode(mpi, SGKS_MDI_CMD_MODE_BLOCK_READY);
    sgks_mpi_cmd_SetMode(mpi, SGKS_MDI_CMD_MODE_NORMAL_LOADING);
    gettimeofday(&tv2, NULL);
    //DEBUGMSG(ZONE_INFO, ("Block Time: %d ms\n", tv2.tv_sec*1000 + tv2.tv_usec/1000 - tv1.tv_sec*1000 - tv1.tv_usec/1000));

    for(i = 0; i < MULTI_STREAM_MAX_NUM; i++)
    {
        if(stream_id & (1 << i))
        {
            if(venc_is_h264_stream(i))
            {
                int flags = VENC_REALTIME_PARAM_QP_LIMIT_BIT |
                            VENC_REALTIME_PARAM_INTRA_MB_ROWS_BIT |
                            VENC_REALTIME_PARAM_INTRA_BIAS_BIT |
                            VENC_REALTIME_PARAM_SCENE_DETECT_BIT;

                ret = venc_cmd_update_encode_params(i, flags);
                if(ret != SGKS_SUCCESS)
                {
                    DEBUGMSG(ZONE_ERROR, ("%s:send update_encode_params command fail\n", __FUNCTION__));
                    return ret;
                }

                pMpiVencHandle->encodeStreams[i].state = VENC_STREAM_STATE_ENCODING;
            }
        }
    }
    return ret;
}

static int venc_encode_stop(u32 stream_id)
{
    int i, encoding_stream;
    sgks_mpi_dsp_status_s   curr_dsp_state;
    int ret = SGKS_SUCCESS;

    ret = sgks_mpi_sys_GetDspStats(&curr_dsp_state);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Get DSP STATE FAIL\n"));
        ret = SGKS_ERR_VENC_DEVICEERR;
    }

    for(i = 0; i < MULTI_STREAM_MAX_NUM; i++)
    {
        if(stream_id & (1 << i))
        {
            if(curr_dsp_state.op_mode == SGKS_DSP_ENCODE_MODE)
            {
                if((curr_dsp_state.state == SGKS_ENC_BUSY_STATE) && venc_is_stream_in_encoding(i))
                {
                    ret = venc_cmd_encode_stop(i);
                    if(ret != SGKS_SUCCESS)
                    {
                        DEBUGMSG(ZONE_ERROR, ("Send encode stop command FAIL\n"));
                        ret = SGKS_ERR_VENC_SENDCMDFAIL;
                    }
                    else
                    {
                        pMpiVencHandle->encodeStreams[i].state = VENC_STREAM_STATE_STOPPING;
                    }
                }
            }
        }
    }

    return ret;
}

// 0x6004 command
static int venc_cmd_update_encode_params(int stream, int flags)
{
    sgks_vi_src_capability_s *vi_cap = NULL;
    sgks_stream_encode_config_s *enc_config = NULL;
    int deintlc_option = 0;
    u32 vi_fps = 0;
    int interlaced = 0;
    int ret = 0;
    sgks_dsp_cmd_ipcam_real_time_encode_param_setup_s dsp_cmd;

    memset(&dsp_cmd, 0x00, sizeof(sgks_dsp_cmd_ipcam_real_time_encode_param_setup_s));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_IPCAM_REAL_TIME_ENCODE_PARAM_SETUP, stream);
    enc_config = pMpiVencHandle->encodeStreams[stream].config;
    interlaced = venc_is_video_capture_interlaced(stream);
    vi_fps = venc_get_vi_capability()->frame_rate;

    if(flags & VENC_REALTIME_PARAM_CBR_MODIFY_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_CBR_MODIFY_BIT;
        dsp_cmd.cbr_modify = enc_config->h264_encode_config.average_bitrate;
    }

    if(flags & VENC_REALTIME_PARAM_CUSTOM_FRAME_RATE_BIT)
    {
        u32 dsp_encoder_fps = 0;
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_CUSTOM_FRAME_RATE_BIT;
        if(venc_calc_encode_frame_rate(vi_fps, interlaced,deintlc_option,
                                       enc_config->frame_rate_multiplication_factor,
                                       enc_config->frame_rate_division_factor, &dsp_encoder_fps) < 0)
        {
            DEBUGMSG(ZONE_ERROR, ("Failed to calculate frame rate from VI 0x%x (CUSTOM_FRAME_RATE).\n", vi_fps));
            return SGKS_ERR_VENC_DEVICEERR;
        }

        dsp_cmd.custom_encoder_frame_rate = dsp_encoder_fps;
        //G_encode_obj.h264_stream_frame_rate[stream] = dsp_encoder_fps; //Delete by liuzejian
        //sys_pts_info->update_fr_flag = 1;  //Delete by liuzejian
        dsp_cmd.frame_rate_division_factor = enc_config->frame_rate_division_factor;
        dsp_cmd.frame_rate_multiplication_factor = enc_config->frame_rate_multiplication_factor;
    }
    if(flags & VENC_REALTIME_PARAM_QP_LIMIT_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_QP_LIMIT_BIT;
        dsp_cmd.qp_max_on_I = enc_config->h264_encode_config.qp_max_on_I;
        dsp_cmd.qp_max_on_P = enc_config->h264_encode_config.qp_max_on_P;
        dsp_cmd.qp_max_on_B = enc_config->h264_encode_config.qp_max_on_B;
        dsp_cmd.qp_min_on_I = enc_config->h264_encode_config.qp_min_on_I;
        dsp_cmd.qp_min_on_P = enc_config->h264_encode_config.qp_min_on_P;
        dsp_cmd.qp_min_on_B = enc_config->h264_encode_config.qp_min_on_B;
        dsp_cmd.aqp = enc_config->h264_encode_config.adapt_qp;
        dsp_cmd.i_qp_reduce = enc_config->h264_encode_config.i_qp_reduce;
        dsp_cmd.p_qp_reduce = enc_config->h264_encode_config.p_qp_reduce;
        dsp_cmd.skip_flags = enc_config->h264_encode_config.skip_flag;
    }
    if(flags & VENC_REALTIME_PARAM_GOP_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_GOP_BIT;
        dsp_cmd.N = enc_config->h264_encode_config.N;
        dsp_cmd.idr_interval = enc_config->h264_encode_config.idr_interval;
    }
    if(flags & VENC_REALTIME_PARAM_CUSTOM_VI_FPS_BIT)
    {
        u32 dsp_vi_fps = 0;
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_CUSTOM_VI_FPS_BIT;
        if(venc_calc_encode_frame_rate(vi_fps, interlaced, deintlc_option, 1, 1, &dsp_vi_fps) < 0)
        {
            DEBUGMSG(ZONE_ERROR, ("Failed to calculate frame rate from VI 0x%x (CUSTOM_VI_FPS).\n", vi_fps));
            return SGKS_ERR_VENC_DEVICEERR;
        }
        dsp_cmd.custom_vi_frame_rate = dsp_vi_fps;
    }
    if(flags & VENC_REALTIME_PARAM_INTRA_MB_ROWS_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_INTRA_MB_ROWS_BIT;
        dsp_cmd.intra_refresh_num_mb_row = enc_config->h264_encode_config.intra_refresh_mb_rows;
    }
    if(flags & VENC_REALTIME_PARAM_PREVIEW_A_FRAME_RATE_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_PREVIEW_A_FRAME_RATE_BIT;
        dsp_cmd.preview_A_frame_rate_divison_factor = 1;
    }
    if(flags & VENC_REALTIME_PARAM_QP_ROI_MATRIX_BIT)
    {
        u8 enable = 0;
        int j = 0;
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_QP_ROI_MATRIX_BIT;
        enable = enc_config->h264_encode_config.qp_roi_enable;

        if(enable)
        {
            if(g_qp_matrix_map.user_addr == NULL)
            {
                DEBUGMSG(ZONE_ERROR, ("Param Error %s\n", __FUNCTION__));
                return SGKS_ERR_VENC_PARAMERR;
            }
            {
                u8 *msg_buf = NULL;
                SGKS_MDI_DRV_BUFF(msg_buf);
                sgks_mdi_opt_d_cache_s *cache = msg_buf;
                cache->start = g_qp_matrix_map.phy_addr + stream * VENC_STREAM_QP_MATRIX_SIZE;
                cache->size = g_qp_matrix_map.size;
                SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
            }
            dsp_cmd.roi_daddr = (u32)(g_qp_matrix_map.phy_addr + stream * VENC_STREAM_QP_MATRIX_SIZE);
        }
        else
        {
            dsp_cmd.roi_daddr = 0;
        }

        for(j = 0; j < SGKS_NUM_PIC_TYPES; ++j)
        {
            dsp_cmd.roi_delta[j][0] = enc_config->h264_encode_config.qp_delta[j][0];
            dsp_cmd.roi_delta[j][1] = enc_config->h264_encode_config.qp_delta[j][1];
            dsp_cmd.roi_delta[j][2] = enc_config->h264_encode_config.qp_delta[j][2];
            dsp_cmd.roi_delta[j][3] = enc_config->h264_encode_config.qp_delta[j][3];
        }
    }
    if(flags & VENC_REALTIME_PARAM_PANIC_MODE_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_PANIC_MODE_BIT;
        dsp_cmd.panic_div = enc_config->h264_encode_config.panic_div;
        dsp_cmd.pic_size_control = enc_config->h264_encode_config.pic_size_control;
    }
    if(flags & VENC_REALTIME_PARAM_QUANT_MATRIX_BIT)
    {
        u8 *quant_matrix_addr_phy = NULL;
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_QUANT_MATRIX_BIT;
        venc_init_stream_jpeg_dqt(stream, enc_config->jpeg_encode_config.quality);
        {
            u8 *msg_buf = NULL;
            u32 addr_offset = 0;

            SGKS_MDI_DRV_BUFF(msg_buf);
            sgks_mdi_opt_d_cache_s *cache = (sgks_mdi_opt_d_cache_s *)msg_buf;
            cache->cache_type = SGKS_OPT_D_CACHE_CLAEN;

            //Get virturall address
            addr_offset = (u32)(enc_config->jpeg_encode_config.jpeg_quant_matrix - g_quant_matrix_addr.user_addr);
            //Then get physical address
            quant_matrix_addr_phy = g_quant_matrix_addr.phy_addr + addr_offset;
            cache->start =   quant_matrix_addr_phy;
            cache->size = JPEG_QT_SIZE;
            SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
        }
        dsp_cmd.quant_matrix_addr = (u32)quant_matrix_addr_phy;
    }
    if(flags & VENC_REALTIME_PARAM_MONOCHROME_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_MONOCHROME_BIT;

        if(venc_is_h264_stream(stream))
        {
            dsp_cmd.is_monochrome = enc_config->h264_encode_config.chroma_format;
        }
        else if(venc_is_mjpeg_stream(stream))
        {
            if(enc_config->jpeg_encode_config.chroma_format ==  VENC_JPEG_CHROMA_FORMAT_YUV420)
            {
                dsp_cmd.is_monochrome = 0;
            }
            else if(enc_config->jpeg_encode_config.chroma_format == VENC_JPEG_CHROMA_FORMAT_MONO)
            {
                dsp_cmd.is_monochrome = 1;
            }
            else
            {
                dsp_cmd.is_monochrome = 0;
            }
        }
    }
    if(flags & VENC_REALTIME_PARAM_INTRA_BIAS_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_INTRA_BIAS_BIT;
        dsp_cmd.P_IntraBiasAdd = enc_config->h264_encode_config.intrabias_P;
        dsp_cmd.B_IntraBiasAdd = enc_config->h264_encode_config.intrabias_B;
    }

    if(flags & VENC_REALTIME_PARAM_BIAS_VALUE_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_BIAS_VALUE_BIT;
        dsp_cmd.intra16x16_bias = enc_config->h264_encode_config.intra16x16_bias;
        dsp_cmd.intra4x4_bias = enc_config->h264_encode_config.intra4x4_bias;
        dsp_cmd.inter16x16_bias = enc_config->h264_encode_config.inter16x16_bias;
        dsp_cmd.inter8x8_bias = enc_config->h264_encode_config.inter8x8_bias;
        dsp_cmd.direct16x16_bias = enc_config->h264_encode_config.direct16x16_bias;
        dsp_cmd.direct8x8_bias = enc_config->h264_encode_config.direct8x8_bias;
        dsp_cmd.me_lambda_qp_offset = enc_config->h264_encode_config.me_lambda_qp_offset;
        dsp_cmd.alpha = enc_config->h264_encode_config.slice_alpha_c0_offset_div2;
        dsp_cmd.beta = enc_config->h264_encode_config.slice_beta_offset_div2;
    }
    if(flags & VENC_REALTIME_PARAM_SCENE_DETECT_BIT)
    {
        dsp_cmd.enable_flags |= VENC_REALTIME_PARAM_SCENE_DETECT_BIT;
        dsp_cmd.scene_change_detect_on = enc_config->h264_encode_config.enable_scene_detect;
    }
    vi_cap = venc_get_vi_capability();
    if((vi_cap->input_type == SGKS_VIDEO_TYPE_YUV_656) && (interlaced == SGKS_VIDEO_FORMAT_INTERLACE))
    {
        dsp_cmd.enable_flags = 0;
    }

    mpi_cmd_hex(dsp_cmd, cmd_code);
    if(flags & VENC_REALTIME_PARAM_CBR_MODIFY_BIT)
    {
        mpi_cmd(dsp_cmd, cbr_modify);
    }

    if(flags & VENC_REALTIME_PARAM_CUSTOM_FRAME_RATE_BIT)
    {
        mpi_cmd_hex(dsp_cmd, custom_encoder_frame_rate);
        mpi_cmd(dsp_cmd, frame_rate_division_factor);
        mpi_cmd(dsp_cmd, frame_rate_multiplication_factor);
    }

    if(flags & VENC_REALTIME_PARAM_QP_LIMIT_BIT)
    {
        mpi_cmd(dsp_cmd, qp_min_on_I);
        mpi_cmd(dsp_cmd, qp_max_on_I);
        mpi_cmd(dsp_cmd, qp_min_on_P);
        mpi_cmd(dsp_cmd, qp_max_on_P);
        mpi_cmd(dsp_cmd, qp_min_on_B);
        mpi_cmd(dsp_cmd, qp_max_on_B);
        mpi_cmd(dsp_cmd, aqp);
        mpi_cmd(dsp_cmd, i_qp_reduce);
        mpi_cmd(dsp_cmd, p_qp_reduce);
        mpi_cmd(dsp_cmd, skip_flags);
    }

    if(flags & VENC_REALTIME_PARAM_GOP_BIT)
    {
        mpi_cmd(dsp_cmd, N);
        mpi_cmd(dsp_cmd, idr_interval);
    }

    if(flags & VENC_REALTIME_PARAM_CUSTOM_VI_FPS_BIT)
    {
        mpi_cmd_hex(dsp_cmd, custom_vi_frame_rate);
    }

    if(flags & VENC_REALTIME_PARAM_INTRA_MB_ROWS_BIT)
    {
        mpi_cmd(dsp_cmd, intra_refresh_num_mb_row);
    }

    if(flags & VENC_REALTIME_PARAM_PREVIEW_A_FRAME_RATE_BIT)
    {
        mpi_cmd(dsp_cmd, preview_A_frame_rate_divison_factor);
    }

    if(flags & VENC_REALTIME_PARAM_QP_ROI_MATRIX_BIT)
    {
        mpi_cmd_hex(dsp_cmd, roi_daddr);
        mpi_cmd(dsp_cmd, roi_delta[0][0]);
        mpi_cmd(dsp_cmd, roi_delta[0][1]);
        mpi_cmd(dsp_cmd, roi_delta[0][2]);
        mpi_cmd(dsp_cmd, roi_delta[0][3]);
        mpi_cmd(dsp_cmd, roi_delta[1][0]);
        mpi_cmd(dsp_cmd, roi_delta[1][1]);
        mpi_cmd(dsp_cmd, roi_delta[1][2]);
        mpi_cmd(dsp_cmd, roi_delta[1][3]);
        mpi_cmd(dsp_cmd, roi_delta[2][0]);
        mpi_cmd(dsp_cmd, roi_delta[2][1]);
        mpi_cmd(dsp_cmd, roi_delta[2][2]);
        mpi_cmd(dsp_cmd, roi_delta[2][3]);
    }

    if(flags & VENC_REALTIME_PARAM_PANIC_MODE_BIT)
    {
        mpi_cmd(dsp_cmd, panic_div);
        mpi_cmd(dsp_cmd, pic_size_control);
    }

    if(flags & VENC_REALTIME_PARAM_QUANT_MATRIX_BIT)
    {
        mpi_cmd_hex(dsp_cmd, quant_matrix_addr);
    }

    if(flags & VENC_REALTIME_PARAM_MONOCHROME_BIT)
    {
        mpi_cmd_hex(dsp_cmd, is_monochrome);
    }

    if(flags & VENC_REALTIME_PARAM_INTRA_BIAS_BIT)
    {
        mpi_cmd(dsp_cmd, P_IntraBiasAdd);
        mpi_cmd(dsp_cmd, B_IntraBiasAdd);
    }

    if(flags & VENC_REALTIME_PARAM_SCENE_DETECT_BIT)
    {
        mpi_cmd(dsp_cmd, scene_change_detect_on);
    }

    if(flags & VENC_REALTIME_PARAM_BIAS_VALUE_BIT)
    {
        mpi_cmd(dsp_cmd, intra16x16_bias);
        mpi_cmd(dsp_cmd, intra4x4_bias);
        mpi_cmd(dsp_cmd, inter16x16_bias);
        mpi_cmd(dsp_cmd, inter8x8_bias);
        mpi_cmd(dsp_cmd, direct16x16_bias);
        mpi_cmd(dsp_cmd, direct8x8_bias);
        mpi_cmd(dsp_cmd, me_lambda_qp_offset);
        mpi_cmd(dsp_cmd, alpha);
        mpi_cmd(dsp_cmd, beta);
    }
    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(sgks_dsp_cmd_ipcam_real_time_encode_param_setup_s));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Send 0x6004 command fail %s\n", __FUNCTION__));
    }
    return ret;

}


static int venc_cmd_capture_preview_buffer_setup(int buffer_id)
{
    int cap_width, cap_height;
    int input_win_width, input_win_height;
    int input_win_offset_x, input_win_offset_y;
    sgks_vi_src_capability_s *current_vi_info = NULL;
    int ret = SGKS_SUCCESS;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    current_vi_info = venc_get_vi_capability();
    // issue 0x6002 only when the source buffer is configured to encode type or off type
    if(mpi->system_source_buff[buffer_id].type != SGKS_SOURCE_BUFFER_TYPE_ENCODE)
    {
        return SGKS_SUCCESS;
    }

    switch(buffer_id)
    {
        case SGKS_ENCODE_SOURCE_SECOND_BUFFER:

            if(mpi->system_resource.second_source_buffer_max_width == 0)
            {
                return SGKS_SUCCESS;
            }
            break;

        case SGKS_ENCODE_SOURCE_THIRD_BUFFER:

            if(mpi->system_resource.third_source_buffer_max_width == 0)
            {
                return SGKS_SUCCESS;
            }
            break;

        case SGKS_ENCODE_SOURCE_FOURTH_BUFFER:
            if(mpi->system_resource.fourth_source_buffer_max_width == 0)
            {
                return SGKS_SUCCESS;
            }
            break;

        default:
            return SGKS_ERR_VENC_PARAMERR;
            break;
    }

    cap_width = mpi->system_source_buff[buffer_id].format.width;
    cap_height = mpi->system_source_buff[buffer_id].format.height;
    input_win_width = mpi->system_source_buff[buffer_id].format.input_width;
    input_win_height = mpi->system_source_buff[buffer_id].format.input_height;
    input_win_offset_x = mpi->system_source_buff[buffer_id].format.input_offset_x;
    input_win_offset_y = mpi->system_source_buff[buffer_id].format.input_offset_y;

    {
        sgks_dsp_cmd_ipcam_capture_preview_size_setup_s dsp_cmd;
        memset(&dsp_cmd, 0, sizeof(dsp_cmd));
        dsp_cmd.cmd_code            = SGKS_DSP_CMD_IPCAM_VIDEO_CAPTURE_PREVIEW_SIZE_SETUP;
        dsp_cmd.capture_source      = venc_get_capture_buffer_id(buffer_id);

        if(cap_width == 0 && cap_height == 0)
        {
            dsp_cmd.disabled = 1;
            switch(buffer_id)
            {
                case SGKS_ENCODE_SOURCE_SECOND_BUFFER:
                    dsp_cmd.cap_width  = mpi->system_resource.second_source_buffer_max_width;
                    dsp_cmd.cap_height = mpi->system_resource.second_source_buffer_max_height;
                    break;

                case SGKS_ENCODE_SOURCE_THIRD_BUFFER:
                    dsp_cmd.cap_width  = mpi->system_resource.third_source_buffer_max_width;
                    dsp_cmd.cap_height = mpi->system_resource.third_source_buffer_max_height;
                    break;

                case SGKS_ENCODE_SOURCE_FOURTH_BUFFER:
                    dsp_cmd.cap_width  = mpi->system_resource.fourth_source_buffer_max_width;
                    dsp_cmd.cap_height = mpi->system_resource.fourth_source_buffer_max_height;
                    break;
                default:
                    return SGKS_ERR_VENC_PARAMERR;
                    break;
            }
        }
        else
        {
            dsp_cmd.disabled     = 0;
            dsp_cmd.cap_width    = cap_width;
            dsp_cmd.cap_height   = cap_height;
        }

        if((current_vi_info->video_format == SGKS_VIDEO_FORMAT_PROGRESSIVE) && (mpi->system_source_buff[buffer_id].format.intlc_scan == INTLC_ON))
        {
            dsp_cmd.output_scan_format = 1;
        }
        else if((current_vi_info->video_format == SGKS_VIDEO_FORMAT_INTERLACE) && (mpi->system_source_buff[buffer_id].format.deintlc_for_intlc_vi == DEINTLC_OFF))
        {
            dsp_cmd.output_scan_format = 1;
        }
        else
        {
            dsp_cmd.output_scan_format = 0;
        }

        dsp_cmd.deinterlace_mode   = mpi->system_source_buff[buffer_id].format.deintlc_for_intlc_vi;
        dsp_cmd.input_win_width    = input_win_width;
        dsp_cmd.input_win_height   = input_win_height;
        dsp_cmd.input_win_offset_x = input_win_offset_x;
        dsp_cmd.input_win_offset_y = input_win_offset_y;
        /* Add for n3  dma input*/
        if((mpi->vi_device.vi_deviceinfo[buffer_id].enable == 1) && (mpi->vi_device.vi_deviceinfo[buffer_id].vi_type == SGKS_VI_TYPE_DMA))
        {
            input_win_width = mpi->vi_device.vi_deviceinfo[buffer_id].cap_width;
            input_win_height =  mpi->vi_device.vi_deviceinfo[buffer_id].cap_height;
            dsp_cmd.input_win_offset_x = 10;
            dsp_cmd.input_win_offset_y = 40;

            dsp_cmd.enable_uv_offset   = 1;
            dsp_cmd.input_win_offset_uv_x = 10;
            dsp_cmd.input_win_offset_uv_y = 40;
            dsp_cmd.input_win_width    = input_win_width -dsp_cmd.input_win_offset_x;
            dsp_cmd.input_win_height   = input_win_height - dsp_cmd.input_win_offset_y;
        }

#if 0
        if(dsp_cmd.capture_source == 1)
        {
            u32 verNum, verSubNum, verThirdNum;
            pfw_version = sgks_get_fw_version();
            verNum      = pfw_version->edition_num / 16 * 10 + pfw_version->edition_num % 16;
            verSubNum   = pfw_version->edition_subnum / 16 * 10 + pfw_version->edition_subnum % 16;
            verThirdNum = pfw_version->edition_thirdnum / 16 * 100 + (pfw_version->edition_thirdnum % 16) * 10 + (pfw_version->edition_extraverion >> 4);
            if((verNum < 3)
               ||(verSubNum < 5)
               ||((verNum == 3)&&(verSubNum == 5)&&(verThirdNum < 97)))
            {
                return 0;
            }
            dsp_cmd.cap_width = vo_info->width;
            dsp_cmd.cap_height = vo_info->height;
            G_source_buffer[buffer_id].format.width = vo_info->width;
            G_source_buffer[buffer_id].format.height = vo_info->height;
        }
#endif
        mpi_cmd_hex(dsp_cmd, cmd_code);
        mpi_cmd(dsp_cmd, capture_source);
        mpi_cmd(dsp_cmd, output_scan_format);
        mpi_cmd(dsp_cmd, deinterlace_mode);
        mpi_cmd(dsp_cmd, disabled);
        mpi_cmd(dsp_cmd, cap_width);
        mpi_cmd(dsp_cmd, cap_height);
        mpi_cmd(dsp_cmd, input_win_offset_x);
        mpi_cmd(dsp_cmd, input_win_offset_y);
        mpi_cmd(dsp_cmd, input_win_width);
        mpi_cmd(dsp_cmd, input_win_height);

        int ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(sgks_dsp_cmd_ipcam_capture_preview_size_setup_s));
        if (ret != SGKS_SUCCESS)
        {
            DEBUGMSG(ZONE_ERROR, ("Send cmd 6002 fail. %s\n", __FUNCTION__));
        }
    }
    return ret;
}

int venc_cmd_encode_size_setup(int stream)
{
    s16 offset_y;
    int ret =SGKS_SUCCESS;
    int interlaced = venc_is_video_capture_interlaced(stream);
    u16 encode_width, encode_height, roundup_width, roundup_height, rotate_flag;
    int intlc_vi_intlc_enc = venc_is_video_encode_interlaced(stream);
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    //call DSP cmd 0x6003 to setup encode size
    sgks_dsp_cmd_ipcam_video_encode_size_setup_s dsp_cmd;
    sgks_mpi_venc_format_s *format;

    format = &pMpiVencHandle->encodeStreams[stream].format;

    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_IPCAM_VIDEO_ENCODE_SIZE_SETUP, stream);
    dsp_cmd.capture_source = venc_get_capture_buffer_id(format->source);

    //use origin encode width, height, VI info and encode type to calculate possible encode size alignment
    rotate_flag = venc_is_h264_stream(stream) ?
                  pMpiVencHandle->encodeStreams[stream].config->h264_encode_config.rotate_clockwise :
                  pMpiVencHandle->encodeStreams[stream].config->jpeg_encode_config.rotate_clockwise;

    if(rotate_flag)
    {
        encode_width = format->encode_height;
        encode_height = format->encode_width;
    }
    else
    {
        encode_width = format->encode_width;
        encode_height = format->encode_height;
    }

	#if 0 //add by ty for test  encode
	encode_width = 3840;
    encode_height = 540;
	#endif
    venc_buffer_size_roundup(intlc_vi_intlc_enc, format->encode_type, encode_width,
                             encode_height, &roundup_width, &roundup_height);

    dsp_cmd.enc_x = format->encode_x;

    /* Use negative offset to compensate h264 top & left cropping flag */
    if(venc_is_h264_stream(stream))
    {
        venc_calc_h264_offset_y(stream, roundup_width, roundup_height, &offset_y);
    }
    else
    {
        offset_y = format->encode_y;
    }

    dsp_cmd.enc_y = offset_y;
    dsp_cmd.enc_width = roundup_width;
    dsp_cmd.enc_height = roundup_height;

    if(format->enable_individual_y_uv_offset == 0)
    {

        int i = 0, dma_en = 0;
        for (i=0; i<mpi->vi_device.vi_device_num; i++)
        {
            if (mpi->vi_device.vi_deviceinfo[stream].vi_type== SGKS_VI_TYPE_DMA &&
                mpi->vi_device.vi_deviceinfo[stream].enable == 1)
            {
                dma_en = 1;
                break;
            }
        }
        if(dma_en == 1)
        {
            /*dvp data lack of 40 line ,force set up the encode height to 672*/
            if (mpi->vi_device.vi_deviceinfo[stream].interface_type==SGKS_VI_INTERFACE_DVP)
            {
                dsp_cmd.enc_width   = ((dsp_cmd.enc_width - 8) >> 4) << 4;
                dsp_cmd.enc_height  = ((dsp_cmd.enc_height - 32) >> 4) << 4;
                dsp_cmd.enc_x = 8;
                dsp_cmd.enc_y = 32;
            }
        }
#if 0
        if(dsp_cmd.capture_source == 3)
        {
            dsp_cmd.enc_width   = ((dsp_cmd.enc_width - 8) >> 4) << 4;
            dsp_cmd.enc_height  = ((dsp_cmd.enc_height - 32) >> 4) << 4;
            dsp_cmd.enc_x               = 8;
            dsp_cmd.enc_y               = 32;
        }
#endif
    }
    else
    {
        dsp_cmd.enable_individual_y_uv_offset = format->enable_individual_y_uv_offset;
        dsp_cmd.enc_uv_x    = format->encode_uv_x;
        dsp_cmd.enc_uv_y    = format->encode_uv_y;
    }

    mpi_cmd_hex(dsp_cmd, cmd_code);
    mpi_cmd(dsp_cmd, capture_source);
    mpi_cmd(dsp_cmd, enc_x);
    mpi_cmd(dsp_cmd, enc_y);
    mpi_cmd(dsp_cmd, enc_width);
    mpi_cmd(dsp_cmd, enc_height);
    mpi_cmd(dsp_cmd, enable_individual_y_uv_offset);
    mpi_cmd(dsp_cmd, enc_uv_x);
    mpi_cmd(dsp_cmd, enc_uv_y);

    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s:send command 0x%x fail\n", __FUNCTION__, dsp_cmd.cmd_code));
    }

    return ret;
}

static int venc_cmd_warp_control(sgks_venc_digital_zoom_s *digital_zoom)
{
#define MaxHorStillGrid             (94) // 6000/64
#define MaxVerStillGrid             (64) // 4000/64
    int ret = SGKS_SUCCESS;
    sgks_vi_src_capability_s *current_vi_info = venc_get_vi_capability();

    if(g_hor_still_warp_table.user_addr == NULL)
    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        g_hor_still_warp_table.size = MaxHorStillGrid*MaxVerStillGrid*sizeof(s16);
        memcpy(msg_buf, (u8 *)&g_hor_still_warp_table, sizeof(sgks_mdi_mem_s));
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_MALLOC, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
        memcpy((u8 *)&g_hor_still_warp_table, msg_buf, sizeof(sgks_mdi_mem_s));
        memset(g_hor_still_warp_table.user_addr, 0x00, MaxHorStillGrid*MaxVerStillGrid*sizeof(s16));
    }

    if(g_ver_still_warp_table.user_addr == NULL)
    {
        u8 *msg_buf = NULL;
        SGKS_MDI_DRV_BUFF(msg_buf);
        g_ver_still_warp_table.size = MaxHorStillGrid*MaxVerStillGrid*sizeof(s16);
        memcpy(msg_buf, (u8 *)&g_ver_still_warp_table, sizeof(sgks_mdi_mem_s));
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_MALLOC, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
        memcpy((u8 *)&g_ver_still_warp_table, msg_buf, sizeof(sgks_mdi_mem_s));
        memset(g_ver_still_warp_table.user_addr, 0x00, MaxHorStillGrid*MaxVerStillGrid*sizeof(s16));
    }

    sgks_dsp_cmd_set_warp_control_s dsp_cmd;
    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = SGKS_DSP_CMD_SET_WARP_CONTROL;
    dsp_cmd.actual_left_top_x = 0;
    dsp_cmd.actual_left_top_y = 0;
    dsp_cmd.actual_right_bot_x = current_vi_info->cap_width << 16;
    dsp_cmd.actual_right_bot_y = current_vi_info->cap_height << 16;
    dsp_cmd.zoom_x = digital_zoom->zoom_factor_x;
    dsp_cmd.zoom_y = digital_zoom->zoom_factor_y;
    dsp_cmd.x_center_offset = digital_zoom->center_offset_x;
    dsp_cmd.y_center_offset = digital_zoom->center_offset_y;
    dsp_cmd.warp_horizontal_table_address = g_hor_still_warp_table.phy_addr;
    dsp_cmd.grid_array_width = 0;
    dsp_cmd.grid_array_height = 0;
    dsp_cmd.horz_grid_spacing_exponent = 0;
    dsp_cmd.warp_vertical_table_address = g_ver_still_warp_table.phy_addr;
    dsp_cmd.vert_warp_enable = 0;
    dsp_cmd.vert_warp_grid_array_width = 0;
    dsp_cmd.vert_warp_grid_array_height = 0;
    dsp_cmd.vert_warp_horz_grid_spacing_exponent = 0;
    dsp_cmd.vert_warp_vert_grid_spacing_exponent = 0;
    mpi_cmd_hex(dsp_cmd, cmd_code);
    mpi_cmd(dsp_cmd, actual_right_bot_x);
    mpi_cmd(dsp_cmd, actual_right_bot_y);
    mpi_cmd(dsp_cmd, zoom_x);
    mpi_cmd(dsp_cmd, zoom_y);
    mpi_cmd(dsp_cmd, x_center_offset);
    mpi_cmd(dsp_cmd, y_center_offset);
    mpi_cmd_hex(dsp_cmd, warp_horizontal_table_address);
    mpi_cmd_hex(dsp_cmd, warp_vertical_table_address);
    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Send cmd 2129 fail. %s\n", __FUNCTION__));
    }
    return ret;

}

static int venc_cmd_h264_encode_setup(int stream)
{
    int ret = SGKS_SUCCESS;
    sgks_venc_h264_config_s *config;
    sgks_dsp_cmd_h264_encode_setup_s dsp_cmd;
    u32 encoder_frame_rate;
    int deintlc_option;
    u32 pjpeg_buffer_start, pjpeg_buffer_size;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();
    int interlaced = venc_is_video_capture_interlaced(stream);

    if(stream >= MULTI_STREAM_MAX_NUM)
    {
        DEBUGMSG(ZONE_ERROR, ("stream id > 4\n"));
        return SGKS_ERR_VENC_PARAMERR;
    }
    config = &(pMpiVencHandle->encodeStreams[stream].config->h264_encode_config);
    deintlc_option = mpi->system_source_buff[pMpiVencHandle->encodeStreams[stream].format.source].format.deintlc_for_intlc_vi;
    if(venc_calc_encode_frame_rate(venc_get_vi_capability()->frame_rate,
                                   interlaced, deintlc_option, pMpiVencHandle->encodeStreams[stream].config->frame_rate_multiplication_factor,
                                   pMpiVencHandle->encodeStreams[stream].config->frame_rate_division_factor, &encoder_frame_rate) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Frame rate 0x%x error %s.\n", venc_get_vi_capability()->frame_rate, __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_H264_ENCODING_SETUP, stream);

    if(interlaced && (deintlc_option == DEINTLC_OFF))
    {
        dsp_cmd.mode = 2;    // PAFF_ALL_FLD
    }
    else
    {
        dsp_cmd.mode = 1;    // PAFF_ALL_FRM
    }

    dsp_cmd.M = config->M;
    dsp_cmd.N = config->N < 255 ? config->N : 255;
    dsp_cmd.idr_interval = config->idr_interval;
    dsp_cmd.quality = venc_calc_quality_model(config);
    dsp_cmd.average_bitrate = config->average_bitrate;
    dsp_cmd.vbr_setting = config->bitrate_control;
    dsp_cmd.vbr_cntl = 0;
    dsp_cmd.hflip = config->hflip;
    dsp_cmd.vflip = config->vflip;
    dsp_cmd.rotate = config->rotate_clockwise;
    dsp_cmd.chroma_format = config->chroma_format;
    dsp_cmd.audio_in_freq = 2;    // todo,   48KHz

    if(venc_get_vi_capability()->frame_rate != 0)
    {
        dsp_cmd.vi_frame_rate = 512000000 / venc_get_vi_capability()->frame_rate; //this one is now obsolette, set to 0 temporarily
    }
    else
    {
        dsp_cmd.vi_frame_rate = 25;
    }

    dsp_cmd.vi_frame_rate_ext  = 0x00; //set to 0 temporarily
    u32 session_id;
    if(SGKS_SUCCESS != venc_get_session_id(stream, &session_id))
    {
        DEBUGMSG(ZONE_ERROR, ("%s get session id fail\n", __FUNCTION__));
        return SGKS_ERR_VENC_DEVICEERR;
    }
    dsp_cmd.session_id = session_id;
    dsp_cmd.custom_encoder_frame_rate = encoder_frame_rate;
    dsp_cmd.frame_rate_division_factor = pMpiVencHandle->encodeStreams[stream].config->frame_rate_division_factor;
    dsp_cmd.frame_rate_multiplication_factor = pMpiVencHandle->encodeStreams[stream].config->frame_rate_multiplication_factor;
    dsp_cmd.force_intlc_tb_iframe = 0;

    //Just only support CABAC, don't support CAVLC!
    dsp_cmd.pjpg_bits_fifo_base = 0;
    dsp_cmd.pjpg_bits_fifo_limit = 0;

    dsp_cmd.cpb_buf_idc = config->cpb_buf_idc;
    dsp_cmd.cpb_cmp_idc = config->cpb_cmp_idc;
    dsp_cmd.en_panic_rc = config->en_panic_rc;
    dsp_cmd.fast_rc_idc = config->fast_rc_idc;
    dsp_cmd.cpb_user_size = config->cpb_user_size;
    mpi_cmd_hex(dsp_cmd, cmd_code);
    mpi_cmd(dsp_cmd, mode);
    mpi_cmd(dsp_cmd, M);
    mpi_cmd(dsp_cmd, N);
    mpi_cmd(dsp_cmd, idr_interval);
    mpi_cmd(dsp_cmd, cpb_user_size);
    mpi_cmd(dsp_cmd, numRef_P);
    mpi_cmd(dsp_cmd, numRef_B);
    mpi_cmd(dsp_cmd, quality);
    mpi_cmd(dsp_cmd, average_bitrate);
    mpi_cmd(dsp_cmd, vbr_setting);
    mpi_cmd(dsp_cmd, vbr_cntl);
    mpi_cmd_hex(dsp_cmd, bits_fifo_base);
    mpi_cmd_hex(dsp_cmd, bits_fifo_limit);
    mpi_cmd_hex(dsp_cmd, info_fifo_base);
    mpi_cmd_hex(dsp_cmd, info_fifo_limit);
    mpi_cmd(dsp_cmd, audio_in_freq);
    mpi_cmd(dsp_cmd, vi_frame_rate);
    mpi_cmd(dsp_cmd, vi_frame_rate_ext);
    mpi_cmd_hex(dsp_cmd, custom_encoder_frame_rate);
    mpi_cmd_hex(dsp_cmd, pjpg_bits_fifo_base);
    mpi_cmd_hex(dsp_cmd, pjpg_bits_fifo_limit);
    mpi_cmd(dsp_cmd, session_id);
    mpi_cmd(dsp_cmd, frame_rate_division_factor);
    mpi_cmd(dsp_cmd, frame_rate_multiplication_factor);
    mpi_cmd(dsp_cmd, hflip);
    mpi_cmd(dsp_cmd, vflip);
    mpi_cmd(dsp_cmd, rotate);
    mpi_cmd(dsp_cmd, chroma_format);
    mpi_cmd(dsp_cmd, cpb_buf_idc);
    mpi_cmd(dsp_cmd, cpb_cmp_idc);
    mpi_cmd(dsp_cmd, en_panic_rc);
    mpi_cmd(dsp_cmd, fast_rc_idc);
    mpi_cmd(dsp_cmd, cpb_user_size);

    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Send cmd 1002 fail. %s\n", __FUNCTION__));
    }
    return ret;
}



//stream 0 ~ 3 multi stream
static int venc_cmd_jpeg_encode_setup(int stream, int is_mjpeg)
{
    int ret = SGKS_SUCCESS;
    u32 encoder_frame_rate, ff_multi, ff_division;
    int deintlc_option;
    u32 jpeg_quant_matrix_phy_addr = 0;
    sgks_venc_mjpeg_config_s *config;
    int interlaced = venc_is_video_capture_interlaced(stream);
    sgks_dsp_cmd_jpeg_encode_setup_s dsp_cmd;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    if(stream >= MULTI_STREAM_MAX_NUM)
    {
        DEBUGMSG(ZONE_ERROR, ("stream id > 4\n"));
        return SGKS_ERR_VENC_PARAMERR;
    }
    config = &(pMpiVencHandle->encodeStreams[stream].config->jpeg_encode_config);
    deintlc_option =  mpi->system_source_buff[pMpiVencHandle->encodeStreams[stream].format.source].format.deintlc_for_intlc_vi;
    ff_multi = pMpiVencHandle->encodeStreams[stream].config->frame_rate_multiplication_factor;
    ff_division = pMpiVencHandle->encodeStreams[stream].config->frame_rate_division_factor;

    if(venc_calc_encode_frame_rate(venc_get_vi_capability()->frame_rate,
                                   interlaced, deintlc_option, ff_multi, ff_division, &encoder_frame_rate) < 0)
    {
        DEBUGMSG(ZONE_ERROR, ("Frame rate 0x%x error.%s\n", venc_get_vi_capability()->frame_rate, __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }

    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_JPEG_ENCODING_SETUP, stream);
    dsp_cmd.chroma_format = config->chroma_format;      // YUV420 or Mono
    dsp_cmd.is_mjpeg = is_mjpeg;
    venc_init_stream_jpeg_dqt(stream, config->quality);
    {
        u8 *msg_buf = NULL;
        u32 addr_offset = 0;

        SGKS_MDI_DRV_BUFF(msg_buf);
        sgks_mdi_opt_d_cache_s *cache = (sgks_mdi_opt_d_cache_s *)msg_buf;
        cache->cache_type = SGKS_OPT_D_CACHE_CLAEN;
        //Get virturall address
        addr_offset = (u32)(config->jpeg_quant_matrix - g_quant_matrix_addr.user_addr);
        //Then get physical address
        jpeg_quant_matrix_phy_addr = g_quant_matrix_addr.phy_addr + addr_offset;

        cache->start =   jpeg_quant_matrix_phy_addr;
        cache->size = JPEG_QT_SIZE;
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }
    dsp_cmd.quant_matrix_addr = (u32 *)jpeg_quant_matrix_phy_addr;
    dsp_cmd.custom_encoder_frame_rate = encoder_frame_rate;   //29.97 progressive
    dsp_cmd.frame_rate_division_factor = ff_division;
    dsp_cmd.frame_rate_multiplication_factor = ff_multi;
    u32 session_id;
    if(SGKS_SUCCESS != venc_get_session_id(stream, &session_id))
    {
        DEBUGMSG(ZONE_ERROR, ("%s get session id fail\n", __FUNCTION__));
        return SGKS_ERR_VENC_DEVICEERR;
    }
    dsp_cmd.session_id = session_id;
    dsp_cmd.hflip = config->hflip;
    dsp_cmd.vflip = config->vflip;
    dsp_cmd.rotate = config->rotate_clockwise;
    mpi_cmd_hex(dsp_cmd, cmd_code);
    mpi_cmd(dsp_cmd, chroma_format);
    mpi_cmd_hex(dsp_cmd, bits_fifo_base);
    mpi_cmd_hex(dsp_cmd, bits_fifo_limit);
    mpi_cmd_hex(dsp_cmd, info_fifo_base);
    mpi_cmd_hex(dsp_cmd, info_fifo_limit);
    mpi_cmd_hex(dsp_cmd, quant_matrix_addr);
    mpi_cmd_hex(dsp_cmd, custom_encoder_frame_rate);
    mpi_cmd(dsp_cmd, session_id);
    mpi_cmd(dsp_cmd, frame_rate_division_factor);
    mpi_cmd(dsp_cmd, frame_rate_multiplication_factor);
    mpi_cmd(dsp_cmd, hflip);
    mpi_cmd(dsp_cmd, vflip);
    mpi_cmd(dsp_cmd, rotate);

    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("Send cmd 1002 fail. %s\n", __FUNCTION__));
    }

    return ret;
}

static int venc_cmd_h264_encode_start(int stream)
{
    int stream_height, buffer_id;
    int ret = SGKS_SUCCESS;
    sgks_dsp_cmd_h264_encode_s dsp_cmd;
    int interlaced = venc_is_video_capture_interlaced(stream);
    int interlaced_video = venc_is_video_encode_interlaced(stream);
    sgks_venc_h264_config_s *config = &(pMpiVencHandle->encodeStreams[stream].config->h264_encode_config);
    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_H264_ENCODE, stream);
    dsp_cmd.start_encode_frame_no = 0xffffffff;
    dsp_cmd.encode_duration = 0xffffffff;
    dsp_cmd.is_flush = 1;
    dsp_cmd.enable_slow_shutter = 0;
    dsp_cmd.res_rate_min = 40;
    dsp_cmd.en_loop_filter = 2;
    dsp_cmd.max_upsampling_rate = 1;
    dsp_cmd.slow_shutter_upsampling_rate = 0;
    dsp_cmd.vui_enable = 1;
    dsp_cmd.timing_info_present_flag = 1;
    dsp_cmd.fixed_frame_rate_flag = 1;
    dsp_cmd.pic_struct_present_flag = 1;
    dsp_cmd.nal_hrd_parameters_present_flag = 1;
    dsp_cmd.vcl_hrd_parameters_present_flag = 1;
    dsp_cmd.video_signal_type_present_flag = 1;
    dsp_cmd.video_full_range_flag = 1;
    dsp_cmd.video_format = 5;
    dsp_cmd.au_type = config->au_type;
    // color primaries
    {
        u32 color_primaries = 1;
        u32 transfer_characteristics = 1;
        u32 matrix_coefficients = 1;
        venc_get_colour_primaries(stream, &color_primaries, &transfer_characteristics, &matrix_coefficients);
        dsp_cmd.colour_description_present_flag = 1;
        dsp_cmd.colour_primaries = color_primaries;
        dsp_cmd.transfer_characteristics = transfer_characteristics;
        dsp_cmd.matrix_coefficients = matrix_coefficients;
    }
    // crop pictures when needed for height alignment
    stream_height = pMpiVencHandle->encodeStreams[stream].format.encode_height;
    {
        u32 round_factor, round_height, margin;
        //hardware needs encoding height to be 16 aligned,
        //for interlaced video, each field needs to be 16 aligned in height
        round_factor = interlaced_video ? 32 : 16;
        dsp_cmd.frame_cropping_flag = 1;
        dsp_cmd.frame_crop_left_offset = 0;
        dsp_cmd.frame_crop_right_offset = 0;
        dsp_cmd.frame_crop_top_offset = 0;
        dsp_cmd.frame_crop_bottom_offset = 0;
        round_height = ROUND_UP(stream_height, round_factor);
        margin = round_height - stream_height;
        margin = interlaced_video ? (margin >> 2) : (margin >> 1);

        if(config->rotate_clockwise)
        {
            /* Use minus height offset to compensate left cropping flag, so use
             * right cropping flag all the time.
             */
            dsp_cmd.frame_crop_right_offset = margin;
        }
        else
        {
            /* Use minus height offset to compensate top cropping flag, so
             * use bottom cropping flag all the time.
             */
            dsp_cmd.frame_crop_bottom_offset = margin;
        }

        if(dsp_cmd.frame_crop_left_offset == 0 &&
           dsp_cmd.frame_crop_right_offset == 0 &&
           dsp_cmd.frame_crop_top_offset == 0 &&
           dsp_cmd.frame_crop_bottom_offset == 0)
        {
            dsp_cmd.frame_cropping_flag = 0;
        }
    }
    // add aspect ratio info in SPS
    {
        u8 aspect_ratio_idc = 0;
        u16 sar_width = 1;
        u16 sar_height = 1;
        buffer_id = pMpiVencHandle->encodeStreams[stream].format.source;
        venc_get_aspect_ratio(buffer_id, &aspect_ratio_idc, &sar_width, &sar_height);

        if(buffer_id != SGKS_ENCODE_SOURCE_MAIN_BUFFER)
        {
            buffer_id = SGKS_ENCODE_SOURCE_MAIN_BUFFER;
            venc_get_aspect_ratio(buffer_id, &aspect_ratio_idc, &sar_width, &sar_height);
        }

        if(sar_width == sar_height)
        {
            // square pixel, 1:1
            sar_width = sar_height = 0;
        }

        dsp_cmd.aspect_ratio_idc = aspect_ratio_idc;
        dsp_cmd.SAR_width = sar_width;
        dsp_cmd.SAR_height = sar_height;
        dsp_cmd.aspect_ratio_info_present_flag = 1;
        dsp_cmd.high_profile = config->high_profile;
    }
    mpi_cmd_hex(dsp_cmd, cmd_code);
    mpi_cmd(dsp_cmd, start_encode_frame_no);
    mpi_cmd(dsp_cmd, is_flush);
    mpi_cmd(dsp_cmd, enable_slow_shutter);
    mpi_cmd(dsp_cmd, res_rate_min);
    mpi_cmd(dsp_cmd, en_loop_filter);
    mpi_cmd(dsp_cmd, max_upsampling_rate);
    mpi_cmd(dsp_cmd, slow_shutter_upsampling_rate);
    mpi_cmd(dsp_cmd, vui_enable);
    mpi_cmd(dsp_cmd, overscan_info_present_flag);
    mpi_cmd(dsp_cmd, overscan_appropriate_flag);
    mpi_cmd(dsp_cmd, video_format);
    mpi_cmd(dsp_cmd, colour_primaries);
    mpi_cmd(dsp_cmd, transfer_characteristics);
    mpi_cmd(dsp_cmd, matrix_coefficients);
    mpi_cmd(dsp_cmd, high_profile);
    mpi_cmd(dsp_cmd, frame_crop_left_offset);
    mpi_cmd(dsp_cmd, frame_crop_right_offset);
    mpi_cmd(dsp_cmd, frame_crop_top_offset);
    mpi_cmd(dsp_cmd, frame_crop_bottom_offset);
    mpi_cmd(dsp_cmd, au_type);
    mpi_cmd(dsp_cmd, aspect_ratio_info_present_flag);
    mpi_cmd(dsp_cmd, aspect_ratio_idc);
    mpi_cmd(dsp_cmd, SAR_width);
    mpi_cmd(dsp_cmd, SAR_height);
    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s: Send command 0x%x fail\n", __FUNCTION__, dsp_cmd.cmd_code));
    }
    return ret;
}

//stream : 0~3  for multi streams
static int venc_cmd_jpeg_encode_start(int stream)
{
    int interlaced = venc_is_video_capture_interlaced(stream);
    int ret = SGKS_SUCCESS;
    sgks_dsp_cmd_mjpeg_capture_s dsp_cmd;
    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_MJPEG_ENCODE, stream);
    dsp_cmd.start_encode_frame_no = -1;
    dsp_cmd.encode_duration = -1;
    mpi_cmd_hex(dsp_cmd, cmd_code);
    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s: Send command 0x%x fail\n", __FUNCTION__, dsp_cmd.cmd_code));
    }
    return ret;
}

static int venc_cmd_encode_stop(int stream)
{
    int interlaced = venc_is_video_capture_interlaced(stream);
    int ret = SGKS_SUCCESS;
    sgks_dsp_cmd_h264_encode_stop_s dsp_cmd;

    memset(&dsp_cmd, 0, sizeof(dsp_cmd));
    dsp_cmd.cmd_code = GET_DSP_CMD_CODE(SGKS_DSP_CMD_ENCODING_STOP, stream);
    // Stop on next P or I picture after stop command has been received.
    dsp_cmd.stop_method = H264_STOP_ON_NEXT_IP;
    mpi_cmd_hex(dsp_cmd, cmd_code);
    mpi_cmd(dsp_cmd, stop_method);
    ret = sgks_mpi_cmd_Send(&dsp_cmd, sizeof(dsp_cmd));
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s: Send command 0x%x fail\n", __FUNCTION__, dsp_cmd.cmd_code));
    }
    return ret;
}

static int venc_feed_yuv_to_encoder(sgks_YuvEncInfo_t *yuvencinfo)
{
    ARM2DSP_EncInfo_t   *encinfo;
    ARM2DSP_HeadInfo_t  *headinfo;
    ARM2DSP_FrameInfo_t *frameinfo;
    u32 next_wr_ptr;
    u8 *msg_buf = NULL;
    u32 encinfo_phy_addr;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    if(yuvencinfo->area_id > 1)
    {
        DEBUGMSG(ZONE_ERROR, ("Error:area_id:%d, must 0 or 1\n", yuvencinfo->area_id));
        return SGKS_ERR_VENC_PARAMERR;
    }
    u32 msg_addr_arm_osd_user_vir = (u32)mpi->mpi_init_param.dsp_init_param.msg_addr_arm_osd_vir;

    encinfo = (ARM2DSP_EncInfo_t *)(msg_addr_arm_osd_user_vir + 512 + yuvencinfo->area_id * sizeof(ARM2DSP_EncInfo_t));
    encinfo_phy_addr = (u32)mpi->mpi_init_param.dsp_init_param.msg_addr_arm_osd_phy + 512 + yuvencinfo->area_id * sizeof(ARM2DSP_EncInfo_t);
    {
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        sgks_mdi_opt_d_cache_s *cache       = msg_buf;
        cache->cache_type                   = SGKS_OPT_D_CACHE_INV;
        cache->start                        = encinfo_phy_addr;
        cache->size                         = sizeof(ARM2DSP_EncInfo_t);
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    headinfo = &(encinfo->headinfo);
    next_wr_ptr = (headinfo->wr_ptr + 1) % 15;
    //DEBUGMSG(ZONE_VENC, ("next_wr_ptr=%d\n", next_wr_ptr));
    //DEBUGMSG(ZONE_VENC, ("y_addr=0x%x\n", yuvencinfo->y_addr));
    //DEBUGMSG(ZONE_VENC, ("uv_addr=0x%x\n", yuvencinfo->uv_addr));
    //DEBUGMSG(ZONE_VENC, ("pitch=%d\n", yuvencinfo->pitch));
    //DEBUGMSG(ZONE_VENC, ("height=%d\n", yuvencinfo->height));
    frameinfo = &(encinfo->frameinfo[next_wr_ptr]);
    frameinfo->y_addr      = yuvencinfo->y_addr;
    frameinfo->uv_addr     = yuvencinfo->uv_addr;
    frameinfo->repeat_nums = yuvencinfo->repeat_nums;
    frameinfo->pitch       = yuvencinfo->pitch;
    frameinfo->height      = yuvencinfo->height;
    headinfo->encode_from_arm_always = yuvencinfo->enc_enable;
    headinfo->prevc_from_arm_always  = yuvencinfo->zoom_enable;
    headinfo->wr_ptr          = next_wr_ptr;
    {
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        sgks_mdi_opt_d_cache_s *cache       = msg_buf;
        cache->cache_type                   = SGKS_OPT_D_CACHE_CLAEN;
        cache->start                        = encinfo_phy_addr;
        cache->size                         = sizeof(ARM2DSP_EncInfo_t);
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }
    return SGKS_SUCCESS;
}

int sgks_mpi_venc_map_encode_buf(sgks_mpi_venc_enc_buf_s *info)
{
    int ret = SGKS_SUCCESS;
    u8 *msg_buf = NULL;
    if((g_enc_buf_map.user_addr != NULL) || (g_enc_buf_map.phy_addr != NULL))
    {
        DEBUGMSG(ZONE_INFO, ("%s: yuv enc buf has alloc!\n", __FUNCTION__));
        info->addr = g_enc_buf_map.user_addr;
        info->length = g_enc_buf_map.size;
        return ret;
    }
    SGKS_MDI_DRV_BUFF(msg_buf);
    g_enc_buf_map.size = VENC_YUV_ENC_BUF_SIZE;
    memcpy(msg_buf, (u8 *)&g_enc_buf_map, sizeof(sgks_mdi_mem_s));
    SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_MALLOC, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    memcpy((u8 *)&g_enc_buf_map, msg_buf, sizeof(sgks_mdi_mem_s));
    memset(g_enc_buf_map.user_addr, 0x00, g_enc_buf_map.size);

    info->addr = g_enc_buf_map.user_addr;
    info->length = g_enc_buf_map.size;
    return ret;
}

int sgks_mpi_venc_unmap_encode_buf()
{
    int ret = SGKS_SUCCESS;
    u8 *msg_buf = NULL;
    SGKS_MDI_DRV_BUFF(msg_buf);
    memcpy(msg_buf, (u8 *)&g_enc_buf_map, sizeof(sgks_mdi_mem_s));
    SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_FREE, 0, sizeof(sgks_mdi_mem_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    memset(&g_enc_buf_map, 0x00, sizeof(g_enc_buf_map));
    return ret;
}

int sgks_mpi_venc_feed_yuv_to_encode(sgks_mpi_venc_yuv_enc_s *info)
{
    int ret;
    sgks_YuvEncInfo_t YuvEncInfo;
    u8 *msg_buf = NULL;
    static int needwait = 0;
    sgks_mpi_manager_s *mpi = mpi_get_managerHanle();

    DEBUGMSG(ZONE_VENC, ("%s\n", __FUNCTION__));
    if((g_enc_buf_map.user_addr == NULL) || (g_enc_buf_map.size == 0) || (g_enc_buf_map.phy_addr == NULL))
    {
        DEBUGMSG(ZONE_ERROR, ("%s: yuv enc buffer has not malloc!\n", __FUNCTION__));
        return SGKS_ERR_VENC_STATEERROR;
    }

    if((info->y_addr  < g_enc_buf_map.user_addr) || (info->y_addr  > (g_enc_buf_map.user_addr + g_enc_buf_map.size)) ||
       (info->uv_addr < g_enc_buf_map.user_addr) || (info->uv_addr > (g_enc_buf_map.user_addr + g_enc_buf_map.size)))
    {
        DEBUGMSG(ZONE_ERROR, ("invalid parameter, y_addr:0x%x, uv_addr:0x%x, user_start:0x%x, user_end:0x%x\n",
                              info->y_addr, info->uv_addr,
                              g_enc_buf_map.user_addr,
                              (g_enc_buf_map.user_addr + g_enc_buf_map.size)));
        return SGKS_ERR_VENC_PARAMERR;
    }

    SGKS_MDI_DRV_BUFF(msg_buf);
    *(u32 *)msg_buf = 3000; //Timeout value
    SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_WAIT_YUV_ENC_COMPLETE, 0, sizeof(u32), SGKS_ERR_SYS_DRIVERIOCTLERR);


    YuvEncInfo.enc_enable = info->enc_enable;
    YuvEncInfo.y_addr      = info->y_addr - (u32)g_enc_buf_map.user_addr + (u32)g_enc_buf_map.phy_addr;
    YuvEncInfo.uv_addr     = info->uv_addr - (u32)g_enc_buf_map.user_addr + (u32)g_enc_buf_map.phy_addr;
    YuvEncInfo.repeat_nums = info->repeat_nums;
    YuvEncInfo.pitch       = info->pitch;
    YuvEncInfo.height      = info->height;
    YuvEncInfo.area_id     = info->area_id;
    YuvEncInfo.zoom_enable = info->zoom_enable;

    {
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        sgks_mdi_opt_d_cache_s *cache       = msg_buf;
        cache->cache_type                   = SGKS_OPT_D_CACHE_CLAEN;
        cache->start                        = YuvEncInfo.y_addr;
        cache->size                         = YuvEncInfo.pitch * YuvEncInfo.height;
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    {
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        sgks_mdi_opt_d_cache_s *cache       = msg_buf;
        cache->cache_type                   = SGKS_OPT_D_CACHE_CLAEN;
        cache->start                        = YuvEncInfo.uv_addr;
        cache->size                         = YuvEncInfo.pitch * YuvEncInfo.height / 2;
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    ret = venc_feed_yuv_to_encoder(&YuvEncInfo);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s:venc_feed_yuv_to_encoder fail\n", __FUNCTION__));
    }
    return ret;
}

int sgks_mpi_venc_yuv_to_jpeg( u32 srcYuv420Addr, u16 srcWidth, u16 srcHeight, u32 *dstJpegAddr, u32 *dstSize)
{
    sgks_mpi_venc_yuv_enc_ex_s *info = NULL;
    u8 *msg_buf = NULL;
    int ret;
    sgks_YuvEncInfo_t YuvEncInfo;
    u32 waitcount = 2;

    if((dstJpegAddr == NULL) ||(dstSize == NULL))
    {
        DEBUGMSG(ZONE_ERROR, ("%s: Param error\n", __FUNCTION__));
        return SGKS_ERR_VENC_PARAMERR;
    }
    info = (sgks_mpi_venc_yuv_enc_ex_s *)sgks_mpi_Malloc(sizeof(sgks_mpi_venc_yuv_enc_ex_s));
    memset(info, 0x00, sizeof(sgks_mpi_venc_yuv_enc_ex_s));

    info->enc_enable  = 1;   //0:means disable encode; 1:means enable encode
    info->zoom_enable = 1;
    info->area_id     = 1;
    info->y_addr      = srcYuv420Addr;
    info->uv_addr     = srcYuv420Addr + srcWidth * srcHeight;
    info->repeat_nums = 0;
    info->pitch       = srcWidth;
    info->height      = srcHeight;

    if((info->y_addr  < g_enc_buf_map.user_addr) || (info->y_addr  > (g_enc_buf_map.user_addr + g_enc_buf_map.size)) ||
       (info->uv_addr < g_enc_buf_map.user_addr) || (info->uv_addr > (g_enc_buf_map.user_addr + g_enc_buf_map.size)))
    {
        DEBUGMSG(ZONE_ERROR, ("invalid parameter, y_addr:0x%x, uv_addr:0x%x, user_start:0x%x, user_end:0x%x\n",
                              info->y_addr, info->uv_addr,
                              g_enc_buf_map.user_addr,
                              (g_enc_buf_map.user_addr + g_enc_buf_map.size)));
        return SGKS_ERR_VENC_PARAMERR;
    }

    YuvEncInfo.enc_enable = info->enc_enable;
    YuvEncInfo.y_addr      = info->y_addr - (u32)g_enc_buf_map.user_addr + (u32)g_enc_buf_map.phy_addr;
    YuvEncInfo.uv_addr     = info->uv_addr - (u32)g_enc_buf_map.user_addr + (u32)g_enc_buf_map.phy_addr;
    YuvEncInfo.repeat_nums = info->repeat_nums;
    YuvEncInfo.pitch       = info->pitch;
    YuvEncInfo.height      = info->height;
    YuvEncInfo.area_id     = info->area_id;
    YuvEncInfo.zoom_enable = info->zoom_enable;
    {
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        sgks_mdi_opt_d_cache_s *cache       = msg_buf;
        cache->cache_type                   = SGKS_OPT_D_CACHE_CLAEN;
        cache->start                        = info->y_addr;
        cache->size                         = info->pitch * info->height;
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    {
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        sgks_mdi_opt_d_cache_s *cache       = msg_buf;
        cache->cache_type                   = SGKS_OPT_D_CACHE_CLAEN;
        cache->start                        = info->uv_addr;
        cache->size                         = info->pitch * info->height / 2;
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_OPT_D_CACHE, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
    }

    ret = venc_feed_yuv_to_encoder(&YuvEncInfo);
    if(ret != SGKS_SUCCESS)
    {
        DEBUGMSG(ZONE_ERROR, ("%s: feed yuv to encode fail\n", __FUNCTION__));
        return ret;
    }

    {
        SGKS_MDI_DRV_BUFF(msg_buf);
        SGKS_MDI_DRV_CLEAN_DATABUFF();
        SGKS_MDI_DRV_IOCTL_EX(pMpiVencHandle->hMDI, SGKS_MDI_OPERATION_GET_YUV_ENC_JPEG_INFO, 0, sizeof(sgks_mdi_opt_d_cache_s), SGKS_ERR_SYS_DRIVERIOCTLERR);
        sgks_mdi_jpeg_info_s JpegDataInfo;
        memcpy(&JpegDataInfo, (sgks_mdi_jpeg_info_s *)msg_buf, sizeof(sgks_mdi_jpeg_info_s));

        *dstJpegAddr = JpegDataInfo.data_addr;
        *dstSize = JpegDataInfo.data_size;
    }
    return ret;
}


